【问题标题】:docker-compose with multiple databasesdocker-compose 与多个数据库
【发布时间】:2016-08-29 10:35:24
【问题描述】:

我试图弄清楚如何使用 docker-compose.yml 和从 sql 转储导入的 2 个数据库来实现 docker。

httpd:
    container_name: webserver
    build: ./webserver/
    ports:
        - 80:80
    links:
        - mysql
        - mysql2
    volumes_from:
        - app

mysql:
    container_name: sqlserver
    image: mysql:latest
    ports:
        - 3306:3306
    volumes:
        - ./sqlserver:/docker-entrypoint-initdb.d
    environment:
        MYSQL_ROOT_PASSWORD: root
        MYSQL_DATABASE: dbname1
        MYSQL_USER: dbuser
        MYSQL_PASSWORD: dbpass

mysql2:
    extends: mysql
    container_name: sqlserver2
    environment:
        MYSQL_ROOT_PASSWORD: root
        MYSQL_DATABASE: dbname2
        MYSQL_USER: dbuser
        MYSQL_PASSWORD: dbpass

app:
    container_name: webdata
    image: php:latest
    volumes:
        - ../php:/var/www/html
    command: "true"

以上返回如下:

Kronos:mybuild avanche$ ./run.sh 
Creating sqlserver
Creating webdata
Creating sqlserver2

ERROR: for mysql2  driver failed programming external connectivity on endpoint sqlserver2 (6cae3dfe7997d3787a8d59a95c1b5164f7431041c1394128c14e5ae8efe647a8): Bind for 0.0.0.0:3306 failed: port is already allocated
Traceback (most recent call last):
  File "<string>", line 3, in <module>
  File "compose/cli/main.py", line 63, in main
AttributeError: 'ProjectError' object has no attribute 'msg'
docker-compose returned -1

基本上,我试图在一个 docker compose 文件中设置我的整个堆栈,创建 2 个数据库并导入各自的 sql 转储。 有人有什么建议吗?

【问题讨论】:

  • 但有什么问题?
  • 基本上,我知道它正在创建另一个mysql容器,但我不知道如何让它重用同一个容器并简单地添加另一个db。

标签: database docker docker-compose


【解决方案1】:

单个 Docker 容器中的多个数据库

本页其他地方的答案为每个数据库设置了一个专用容器,但单个 MySQL 服务器能够托管多个数据库。是否应该is a different question,但如果你想在一个容器中放置多个数据库,here's an example

docker-compose.yml:

version: '3'

volumes:
  db:
    driver: local

  services:
    db:
      image: mysql:5.7
      command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
      volumes:
        - ./docker/provision/mysql/init:/docker-entrypoint-initdb.d
      environment:
        MYSQL_ROOT_PASSWORD: local

docker/provision/mysql/init/01-databases.sql:

# create databases
CREATE DATABASE IF NOT EXISTS `primary`;
CREATE DATABASE IF NOT EXISTS `secondary`;

# create root user and grant rights
CREATE USER 'root'@'localhost' IDENTIFIED BY 'local';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';

这是如何工作的?

这是因为MySQL Docker project 有一个entrypoint script,它将遍历/docker-entrypoint-initdb.d 文件夹中的所有文件(如果存在)。这对于设置数据库和初始化它们的模式和数据很有用。在 docker-compose 中,我们使用 volumes 将该虚拟文件夹映射到主机系统上的文件夹。

【讨论】:

  • (请注意,它被编辑为使用GRANT ALL PRIVILEGES;我个人更喜欢GRANT ALL,因为它更简洁且功能相同(dev.mysql.com/doc/refman/8.0/en/grant.html#grant-privileges),但我不会费心游说恢复它。)
  • 你能说它对 PostgreSQL 是等价的吗?
  • 您还可以在该目录中添加扩展名为 .sh 的 shell 脚本
  • 您能否修复示例代码中的缩进? services 是顶级键,而不是嵌套在 volumes 下(请参阅您的示例链接)。现在这会出错,说db 键'不匹配任何正则表达式:'^x-''(docker 3.7)
  • 看,伙计们,我只是按照这个答案告诉我的去做,但我发现我遇到了一个问题,如果您使用 SQL 文件 (01-databases.sql) 创建一个 root 用户,那么您会出错,因为在设置 MYSQL_ROOT_PASSWORD env 时,MySql docker 映像已经创建了这个 root 用户。您只需创建将在数据库应用程序连接选项中使用的应用程序用户。
【解决方案2】:

您正在尝试将两个数据库容器绑定到同一个端口 - 3306。这基本上是不可能的。 您需要更改其中一个数据库的端口映射,例如mysql 保留3306:3306,而mysql2 应使用3307:3306

【讨论】:

  • 添加:端口:-3307:3306 没有解决它。同样的错误。它可能会忽略扩展容器上的端口吗?
  • @Avanche 我想它确实忽略了。这是 GitHub 上的一个相关问题:github.com/docker/compose/issues/2260
  • 谢谢,不幸的是,我只需要在 dockerfile 中进行操作
  • 用不同端口配置的“image:mysql:latest”替换这个“image:mysql:latest”,然后检查
【解决方案3】:

就像对可能调查此问题的其他人的更新一样。

我通过删除解决了这个问题:

MYSQL_DATABASE: dbname 

来自 docker-compose.yml 并将相关的创建数据库语句直接添加到传递给 docker-entrypoint-initdb.d 的 sql 文件中。

在那个阶段,sql命令是在root下执行的,所以你还需要添加一条语句来授予你要使用的数据库用户相关的权限。

【讨论】:

【解决方案4】:

苦苦挣扎,3天找到了这个Article 解决这个问题救了我的命

文件结构

Project
├── docker-compose.yml (File)
├── init (Directory)
│   ├── 01.sql (File)

然后将 init 目录指向 docker-compose.yml 文件中的卷内,如下所示

volumes: 
  - ./init:/docker-entrypoint-initdb.d

01.sql

CREATE DATABASE IF NOT EXISTS `test`;
GRANT ALL ON `test`.* TO 'user'@'%';

docker-compose.yml

version: '3.6'
    
services: 
    # MySQL
    db:
        image: mysql
        command: --default-authentication-plugin=mysql_native_password
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: root
            MYSQL_DATABASE: mydb
            MYSQL_USER: user
            MYSQL_PASSWORD: user

        volumes: 
            - ./init:/docker-entrypoint-initdb.d
    
    adminer:
        image: adminer
        restart: always
        ports:
            - 8080:8080

【讨论】:

  • 如果我们只想连接到test 数据库并在那里更改架构,您知道该怎么做吗?谢谢。
【解决方案5】:
version: '3'
services:
  mysql1:
    image: mysql:5.6.26
    environment:
     MYSQL_ROOT_PASSWORD: asdf
     MYSQL_USER: asdf
     MYSQL_HOST: localhost
     MYSQL_PASSWORD: asdf
     MYSQL_DATABASE: asdf
    ports:
      - "3307:3306"
  mysql2:
    image: mysql:5.6.26
    environment:
     MYSQL_ROOT_PASSWORD: asdf
     MYSQL_USER: asdf
     MYSQL_HOST: localhost
     MYSQL_PASSWORD: asdf
     MYSQL_DATABASE: asdf
    ports:
      - "3308:3306"
  • docker-compose up之后
  • 连接到mysql1

    mysql -h localhost -uasdf -P 3307 -pasdf asdf --protocol=tcp -D asdf
    
  • 连接到mysql2

    mysql -h localhost -uasdf -P 3308 -pasdf asdf --protocol=tcp -D asdf
    

【讨论】:

  • 您能否为MYSQL_USERMYSQL_ROOT_PASSWORDMYSQL_PASSWORDMYSQL_DATABASE 设置不同的值而不是asdf,以便您的 Connect to mysql 命令具有更清晰。所有asdf 值都有些混乱。谢谢
【解决方案6】:

对我来说,帮助下一个:

  db:
    image: postgres
    container_name: mgt_db
    restart: always
    environment:
      POSTGRES_USER: postgres
      POSTGRES_DB: mgtdb
      POSTGRES_HOST_AUTH_METHOD: trust
    ports:
      - 5432:5432
  db2:
    image: postgres
    container_name: pay_vault_db 
    restart: always
    environment:
      POSTGRES_USER: postgres
      POSTGRES_DB: payvaultdb
      POSTGRES_HOST_AUTH_METHOD: trust
    ports:
      - 5433:5432

【讨论】:

    【解决方案7】:

    在一个容器中运行多个服务

    在我看来,以上答案都不完整。在原始问题中, 我看到有人尝试启动两个容器。运行两个数据库容器是好是坏? Docker 文档说

    通常建议您通过每个容器使用一项服务来区分关注区域。 该服务可能会分叉成多个进程(例如,Apache Web 服务器启动多个工作进程)。可以有多个进程, 但要从 Docker 中获得最大收益,请避免一个容器负责整个应用程序的多个方面。 您可以使用用户定义的网络和共享卷连接多个容器。

    将相同的规则应用于数据库似乎在逻辑上也是正确的。因此,按模式使用数据库容器并没有错。它提供了灵活性。

    下面我添加了更多的网络和固定数据库初始化 优雅的方式。通过扩展“mysql”容器,相同的 3306 端口被暴露为外部 提供从控制台或外部应用程序对 mysql 数据库的访问。 该端口必须是唯一的。为了解决这个错误,我添加了端口映射 mysql2 容器也是如此。这些端口提供对数据库的访问 控制台或外部应用程序。如果应用程序需要数据库访问 仅容器,不需要这些映射。 Docker有自己的 内部 DNS。这就是为什么应用程序容器的数据库连接可以 使用容器名作为域名进行配置。所以,数据库 连接字符串将为 dbuser@mysql:3306/dbname1 和 dbuser@mysql2:3306/dbname2.

    version: '3'
    services:
    
     httpd:
        container_name: webserver
        build: ./webserver/
        ports:
            - 80:80
        links:
            - mysql
            - mysql2
        volumes_from:
            - app
       
     mysql:
        container_name: sqlserver
        image: mysql:latest
        ports:
            - 3306:3306
        volumes:
            - ./dump.sql:/docker-entrypoint-initdb.d/dump.sql
        environment:
            MYSQL_ROOT_PASSWORD: root
            MYSQL_DATABASE: dbname1
            MYSQL_USER: dbuser
            MYSQL_PASSWORD: dbpass
        networks:
          - app-network
       
     mysql2:
        extends: mysql
        container_name: sqlserver2
        ports:
            - 3307:3306
        volumes:
            - ./dump2.sql:/docker-entrypoint-initdb.d/dump.sql
        environment:
            MYSQL_ROOT_PASSWORD: root
            MYSQL_DATABASE: dbname2
            MYSQL_USER: dbuser
            MYSQL_PASSWORD: dbpass
       networks:
          - app2-network
    
     app:
        container_name: webdata
        image: php:latest
        volumes:
            - ../php:/var/www/html
        command: "true"
        networks:
          - app-network
          - app2-network
    
    #Docker Networks
    networks:
      app-network:
      app2-network:
        driver: bridge
    #Volumes
    volumes:
      dbdata:
        driver: local
    

    【讨论】:

      【解决方案8】:

      当您研究 mysql 映像的 /usr/local/bin/docker-entrypoint.sh 时,您会注意到在映射的 docker-entrypoint-initdb.d 中处理 *.sh 文件的不同模式(寻找 HERE 标记): p>

              case "$f" in
                  *.sh)
                      if [ -x "$f" ]; then
                          "$f"
                      else
                          . "$f" # HERE!!
                      fi
                      ;;
                  *.sql)    mysql_note "$0: running $f"; docker_process_sql < "$f"; echo ;; # HERE!!
                  # ...
              esac
      

      使用它,您可以创建一个不带可执行位的000-databases.sh,其中包含以下内容:

      echo "
      CREATE DATABASE IF NOT EXISTS \`other-database\`;
      GRANT ALL PRIVILEGES ON \`other-database\`.* TO '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD';
      " | docker_process_sql
      

      这里的关键实用程序是 docker_process_sql,它处理 SQL 脚本。 MYSQL_* 变量来自您的 docker-compose.yml 环境配置。

      【讨论】:

        【解决方案9】:

        您可以在单个容器服务中拥有多个数据库:

        docker-compose.yml

        version: '3.7'
        services:
          postgres-db:
            restart: always
            image: postgres:latest
            volumes:
              - db-volume:/var/lib/postgresql/data
            ports:
              - "5432:5432"
            env_file:
              - ./db-prod.env
        

        db-prod.env

        POSTGRES_USER=myusername
        POSTGRES_PASSWORD=mypassword
        POSTGRES_MULTIPLE_DATABASES=db1,db2
        

        来源: 1 2 3

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-10-09
          • 1970-01-01
          • 2020-12-28
          • 1970-01-01
          • 2020-04-29
          • 2017-06-03
          • 2021-07-26
          • 1970-01-01
          相关资源
          最近更新 更多