多容器应用与Docker Compose

文章讲述了如何在Docker中将MySQL集成到应用中,强调每个容器应专注于单一任务。通过创建网络使容器间通信,并详细说明了如何启动和连接MySQL容器。还讨论了使用DockerCompose来管理多容器应用,包括编写docker-compose.yaml文件来定义服务和环境变量,以及如何通过DockerCompose启动和管理应用栈。
摘要由CSDN通过智能技术生成

到目前为止,已学会单个容器的应用,现在要把MySQL加入到应用栈中。下面的问题会不会出现—MySQL运行在哪里?把它安装在同一容器中还是分开?通常情况下,每个容器应该只做一件事情并把这件事做好。下面是容器分开运行的原因:

  • 很多时候,要以不同于数据库的方式扩展API和前端。
  • 容器分开可以让你独立的控制版本。
  • 在本地你可以使用一个数据库容器,但在生产环境,可能用的是数据库托管服务,你不希望随着你的应用一同迁移数据库。
  • 运行多个进程需要进程管理器(容器只启动一个进程),这增加了容器启动和停止的复杂性。

还有其他更多的原因,所以如下图所示,最好将应用和数据库分开运行在不同的容器。
image.png

多容器应用

容器网络

是否记得,默认情况下,容器是隔离、独立运行的,不知道同一机器上的其他进程或容器的任何信息。这样的话,如何是一个容器同另一容器通信。答案是网络。如果将两个容器放在同一网络中,彼此之间就可以通信。

动词MySQL

有两种方式将一个容器置于一个网络中:

  • 在启动容器时指定一个网络。
  • 将一个正在运行的容器连接到一个网络。

在下面的步骤中,会首先创建一个网络,然后在启动MySQL容器时关联到这个网络。

  1. 创建网络
docker network create todo-app
  1. 启动MySQL容器,然后连接到上面创建的网络。你也可以定义一些初始化数据库所需的环境变量。想要知道更多的MySQL环境变量信息,查看“MySQL Docker Hub listing”的环境变量章节。
    1. 如果使用的是Mac或Linux,使用下面的命令启动MySQL。
docker run -d \
     --network todo-app --network-alias mysql \
     -v todo-mysql-data:/var/lib/mysql \
     -e MYSQL_ROOT_PASSWORD=secret \
     -e MYSQL_DATABASE=todos \
     mysql:8.0
  1. 如果使用的windows,在PowerShell中,使用下面的命令:
docker run -d `
     --network todo-app --network-alias mysql `
     -v todo-mysql-data:/var/lib/mysql `
     -e MYSQL_ROOT_PASSWORD=secret `
     -e MYSQL_DATABASE=todos `
     mysql:8.0

在上面的命令中,会看到--network-alias,在后续的章节中,会对此标签有详细说明。

在上面的命令中,你会注意到名为todo-mysql-alias的数据卷,此卷被挂载到容器的/var/lib/mysql,这是MySQL容器存储数据的目录。虽然从来没有执行docker volume create命令。Docker认识到你想要使用一个具名的卷,然后会自动为你创建一个。

  1. 为确认数据库已正常启动,连接并确认数据库:
docker exec -it <mysql-container-id> mysql -u root -p

当出现密码输入提示时,录入secret.在MySQL的shell中,列出所有数据库,确认todo数据库存在。

mysql> SHOW DATABASES;

上述命令的输出结果类似下面:

+--------------------+
 | Database           |
 +--------------------+
 | information_schema |
 | mysql              |
 | performance_schema |
 | sys                |
 | todos              |
 +--------------------+
 5 rows in set (0.00 sec)
  1. 退出MySQL的shell,返回到宿主机的shell中。
mysql> exit

连接到MySQL

现在MySQL数据库已启动并运行,就可以使用它。但是,如何使用?如果在同中网络中运行另外一个容器,如何发现另外一容器?记住,每个容器都有自己的ip地址。
为了回答上面的问题并更好的理解容器网络,接下来会使用nicolaka/netshoot容器,该容器附带了很多用于排除、高度网络问题的工具。

  1. 使用nicolaka/netshoot镜像启动一个新的容器。确保和MySQL连接到了同一网络。
docker run -it --network todo-app nicolaka/netshoot
  1. 在容器里,你会用到dig命令,一个好用的DNS工具。找到mysql主机的ip地址:
dig mysql

会看到类似下面的输出:

; <<>> DiG 9.18.8 <<>> mysql
 ;; global options: +cmd
 ;; Got answer:
 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22162
 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

 ;; QUESTION SECTION:
 ;mysql.				IN	A

 ;; ANSWER SECTION:
 mysql.			600	IN	A	172.23.0.3

 ;; Query time: 0 msec
 ;; SERVER: 127.0.0.11#53(127.0.0.11)
 ;; WHEN: Tue Jun 01 23:47:24 UTC 2023
 ;; MSG SIZE  rcvd: 44

在“ANSWER SECTION”,你会看到mysql的一条A记录,解析为172.23.0.3,你的输出结果中,IP地址可能会不同。mysql并不是有效的主机名,Docker会将它解析为具有该网络别名的容器的IP地址,在启动该容器时,使用--network-alias定义的别名。
这意味着你的应用只需要简要的连接到名为mysql的主机,就可以和数据库通信。

连接应用到MySQL容器

待办应用app(http://t.csdn.cn/N4Gkt)支持一些环境变量设置来指定MySQL连接:

  • MYSQL_HOST:MySQL服务器的主机名称。
  • MYSQL_USER:MySQL连接的用户名。
  • MYSQL_PASSWORD:MySQL连接的用户名密码。
  • MYSQL_DB:连接之后使用的数据库名称。

当使用环境变量设置连接时,在开发环境是可以接受的,但在生产环境,非常不推荐这么做。Diogo Monica,Docker的前安全主管,写过一片博客(https://blog.diogomonica.com//2017/03/27/why-you-shouldnt-use-env-variables-for-secret-data/)来解释为什么。
一个更安全的机制是使用容器编排框架提供的架构支持。在多数场景中,这些加密信息被以文件的形式挂载在容器内。也许你看到过很多app(包括MySQL镜像、待办app镜像)也支持使用_file后缀的文件来包含这些环境变量。
举个例子,设置MYSQL_PASSWORD_FILE变量,会使app使用相关文件中的内容做为连接密码。Docker并不需要做其他任何事情来支持这些环境变量。你的app将知道查找环境变量,获取文件内容。

现在可以启动开发就绪的容器。

  1. 为上面提到的每个环境变量赋值,同时将容器连接到网络,确认在getting-started/app目录下执行下面的命令。
    1. 在Mac或Linux上:
docker run -dp 3000:3000 \
   -w /app -v "$(pwd):/app" \
   --network todo-app \
   -e MYSQL_HOST=mysql \
   -e MYSQL_USER=root \
   -e MYSQL_PASSWORD=secret \
   -e MYSQL_DB=todos \
   node:18-alpine \
   sh -c "yarn install && yarn run dev"
  1. 在Windows上:
docker run -dp 3000:3000 `
   -w /app -v "$(pwd):/app" `
   --network todo-app `
   -e MYSQL_HOST=mysql `
   -e MYSQL_USER=root `
   -e MYSQL_PASSWORD=secret `
   -e MYSQL_DB=todos `
   node:18-alpine `
   sh -c "yarn install && yarn run dev"
  1. 如果你查看容器的日志(使用docker logs -f <container-id>),将会看到类似下面的信息,表明在使用MySQL数据库。
nodemon src/index.js
 [nodemon] 2.0.20
 [nodemon] to restart at any time, enter `rs`
 [nodemon] watching dir(s): *.*
 [nodemon] starting `node src/index.js`
 Connected to mysql db at host mysql
 Listening on port 3000
  1. 在浏览器中打开待办app,添加一些事项到待办列表中。
  2. 连接MySQL数据库,证实上面添加的事项已已写入到数据库中。记住,数据库密码是secret
docker exec -it <mysql-container-id> mysql -p todos

在MySQL容器的shell中,执行下面的命令:

mysql> select * from todo_items;
 +--------------------------------------+--------------------+-----------+
 | id                                   | name               | completed |
 +--------------------------------------+--------------------+-----------+
 | 1946ff08-54e6-4446-8249-ed545a0853e5 | Do things!         |         0 |
 +--------------------------------------+--------------------+-----------+

你的数据库表看起来会不一样,因为已经有不同的待办。

Docker Compose

Docker Compose是用来定义、分享多容器应用的工具。使用Compose,可以创建一个YAML文件来定义服务,用一个简单的命令,就可以启动或停止所有服务。
使用Compose最大的好处是可以在一个文件中定义应用栈,并将该文件放在你工程的根目录,可以非常容易的让其他人参与到项目中来。其他他只需要克隆你的工程,然后启动。实际上,在GitHub/GitLab上,有很多工程就是这样做的。

安装Docker Compose

如果你在Windows、Mac或Linux已安装了Docker Desktop(http://t.csdn.cn/8oZpt),那么Docker Compose已经安装。Play-with-Docker实例也已经安装了Docker Compose。
Docker引擎的独立安装要求Docker Compose作为单独的软件包安装。

使用repository安装
  1. 在发行版本说明中找到指导说明,设置repository,不同发行版的设置说明如下:
  • Ubuntu
  1. 更新apt包索引并安装包,以允许apt通过HTTPS使用repository
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
  1. 添加Docker的官方GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
  1. 使用下面的命令设置repository
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  • CentOS

安装yum-utils包,设置repository

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
  • Debian
  1. 更新apt包索引并安装包,以允许apt通过HTTPS使用repository
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
  1. 添加Docker的官方GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
  1. 使用下面的命令设置repository
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  • Fedora

安装dnf-plugins-core包,设置repository

sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
  • RHEL

安装yum-utils包,设置repository

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
  • SLES

设置repository

sudo zypper addrepo https://download.docker.com/linux/sles/docker-ce.repo
  1. 更新包索引,安装最新版本的Docker Compose。
  • 对于Ubuntu和Debian,使用下面的命令
sudo apt-get update
sudo apt-get install docker-compose-plugin
  • 对于基于RPM的发行版,使用下面的命令
sudo yum update
sudo yum install docker-compose-plugin
  1. 通过检查版本确认Docker Compose被正确安装
docker compose version
Docker Compose version vN.N.N

上面的v.N.N.N表示最新的版本号,不同时间点不一样。

更新Docker Compose

使用下面的命令更新Docker Compose

  • 对于Ubuntu和Debian,运行
sudo apt-get update
sudo apt-get install docker-compose-plugin
  • 对于基于RPM的发行版,运行
sudo yum update
sudo yum install docker-compose-plugin
手动安装

这种安装方式安装,后续升级的话,只能手动升级。建议设置Docker的repository,来方便后续的维护

  1. 下载和安装Docker Compose的CLI插件,运行:
DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/v2.18.1/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose

上面的命令下载最新版本的Docker Compose,然后在$HOME目录下,为激活的用户安装Docker Compose.
为了安装:

  • 为你系统里所有用户安装Docker Compose,使用/usr/local/lib/docker/cli-plugins替换~/.docker/cli-plugins
  • 不同版本的安装,使用你想用的版本号替换v2.18.1
  • 针对不同的操作系统架构,使用你需要的架构替换x86_x64
  1. 将可执行权限授予二进制文件
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose

或者,如果是为所有用户安装的Docker Compose,则执行:

sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
  1. 验证安装结果
docker compose version
Docker Compose version v2.18.1

创建Compose文件

  1. /getting-started/app的根目录下,创建一个名为docker-compose.yaml的文件。
  2. 在compose文件中,我们首先定义要作为应用程序一部分运行的服务或容器列表。
services:

现在,让我们依次迁移服务到这个文件中。

定义应用服务

记住,这些命令,是我们用来定义我们应用容器的。

docker run -dp 3000:3000 \
  -w /app -v "$(pwd):/app" \
  --network todo-app \
  -e MYSQL_HOST=mysql \
  -e MYSQL_USER=root \
  -e MYSQL_PASSWORD=secret \
  -e MYSQL_DB=todos \
  node:18-alpine \
  sh -c "yarn install && yarn run dev"
  1. 首先,让我们定义服务条目和容器的镜像,可以为服务取任何名称。这个名称会自己变成一个网络的简称,会在定义MySQL服务的时候用到。
services:
  app:
    image: node:18-alpine
  1. 通常,你会看到挨着imagecommand,虽然对顺序没有要求,所以可以随意移动到我们的文件中。
services:
  app:
    image: node:18-alpine
    command: sh -c "yarn install && yarn run dev"
  1. 通过为服务定义port迁移-p 3000:3000这部分命令。这里我们会用短语法,但也有更详细的长语法。
services:
  app:
    image: node:18-alpine
    command: sh -c "yarn install && yarn run dev"
    ports:
      - 3000:3000
  1. 然后,我们通过定义working_dirvolumes来迁移工作目录-w /app和卷映射-v "$(pwd):/app"。卷同样有长短语法。
services:
  app:
    image: node:18-alpine
    command: sh -c "yarn install && yarn run dev"
    ports:
      - 3000:3000
    working_dir: /app
    volumes:
      - ./:/app
  1. 最后,需要使用environment来迁移环境变量
services:
  app:
    image: node:18-alpine
    command: sh -c "yarn install && yarn run dev"
    ports:
      - 3000:3000
    working_dir: /app
    volumes:
      - ./:/app
    environment:
      MYSQL_HOST: mysql
      MYSQL_USER: root
      MYSQL_PASSWORD: secret
      MYSQL_DB: todos

定义MySQL服务

现在该定义MySQL服务了。下面是我们创建MySQL容器的命令。

docker run -d \
  --network todo-app --network-alias mysql \
  -v todo-mysql-data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=secret \
  -e MYSQL_DATABASE=todos \
  mysql:8.0
  1. 先定义名为mysql的新服务,所以自动获取网络简称,继续指定要使用的镜像。
services:
  app:
    # The app service definition
  mysql:
    image: mysql:8.0
  1. 接下来,定义数据卷映射,当我们使用docker run运行容器时,命令的卷被自动创建。但使用Compose启动时,这并不会发生。我们需要定义卷在顶层的volumes:部分,然后在服务配置中指定挂载点。通过简单的提供卷名,默认的配置就被使用了。
services:
  app:
    # The app service definition
  mysql:
    image: mysql:8.0
    volumes:
      - todo-mysql-data:/var/lib/mysql

volumes:
  todo-mysql-data:
  1. 最后,我们仅需要指定环境变量
services:
  app:
    # The app service definition
  mysql:
    image: mysql:8.0
    volumes:
      - todo-mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: todos

volumes:
  todo-mysql-data:

到目前为止,我们完成了docker-compose.yaml文件的定义,如下:

services:
  app:
    image: node:18-alpine
    command: sh -c "yarn install && yarn run dev"
    ports:
      - 3000:3000
    working_dir: /app
    volumes:
      - ./:/app
    environment:
      MYSQL_HOST: mysql
      MYSQL_USER: root
      MYSQL_PASSWORD: secret
      MYSQL_DB: todos

  mysql:
    image: mysql:8.0
    volumes:
      - todo-mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: todos

volumes:
  todo-mysql-data:

运行应用栈(stack)

现在有了docker-compose.yaml,可以启动它。

  1. 首先确认没有应用或数据库的其他复本容器在运行,通过docker ps检查,通过docker rm -f <ids>
  2. 使用docker compose up启动应用栈,添加-d标签,让所有服务在后台运行。
docker compose up -d

当运行上面命令时,我们会看类似下面的输出:

Creating network "app_default" with the default driver
 Creating volume "app_todo-mysql-data" with default driver
 Creating app_app_1   ... done
 Creating app_mysql_1 ... done

你会注意到,卷和网络都被自动创建。默认情况下,Docker Compose自动创建一个网络专门用于应用栈,这就是我们为什么不在文件中定义的原因。

  1. 使用docker compose logs -f命令查看日志。会看到每个服务的日志交织在一个文件中。当你想关注与时间相关的问题时,这会非常有用。-f标签跟踪日志,会实时的展示产生的日志。

如果上面的命令已执行,你会看到类似下面的输出:

mysql_1  | 2023-6-04T01:07:26.083639Z 0 [Note] mysqld: ready for connections.
 mysql_1  | Version: '8.0.31'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
 app_1    | Connected to mysql db at host mysql
 app_1    | Listening on port 3000

服务名称已在行首展示,用于协助区分信息。如果想看指定服务的日志,可以将服务的名称添加到看日志命令的后面,如docker compose logs -f app

  1. 到现在,就可以打开我们的应用,我们使用一个简单的命令做到了这些。

在Docker展板上查看应用栈(stack)

如果查看Docker Desktop的展板,你会看到一个名为app的组,这个名称来自Docker Compose中的项目名,用来将容器聚集在一起。默认情况下,项目名是docker-compose.yaml文件所在的目录。
image.png
点击app旁边的展开按钮,就会看到我们在compose文件中定义的两个容器,容器的名字更具有描述性,格式为<service-name>-<replica-number>。所以非常容易看出来哪个容器是我们的app,哪个容器是我们的MySQL数据库。
image.png

全部停止

准备停止时,仅需要执行docker compose down,或者在Docker Dashboard上点击整个应用程序的垃圾桶。容器会停止,网络会被删除。

默认情况下,执行docker compose down,并不会删除在compose文件中命名的卷。如果想要删除这些卷,需要添加--volumes标签。

一旦停止,就可以转向另外的项目,执行docker compose up,做好准备为项目贡献,没有比这更简要的了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值