目录

1.入门

1.1.命令

1.2.什么是容器?

1.3.什么是容器镜像?

2.应用程序

2.1.新建

2.2.更新

2.2.共享

3.持久化数据库

4.使用绑定挂载

4.1.启动一个开发模式容器

5.多容器应用

5.1.容器网络

5.2.启动 MySQL

5.3.连接到 MySQL

6.使用 Docker Compose

6.1.安装 Docker Compose 

 6.2.创建 Compose 文件

6.3.定义应用服务

6.4.定义 MySQL 服务

6.5.运行应用程序

6.6.停止

7.镜像构建最佳实践

7.1.安全扫描

7.2.镜像分层

7.3.图层缓存

7.4.多阶段构建


1.入门

1.1.命令

docker run -d -p 80:80 docker/getting-started
# 组合标志命令
docker run -dp 80:80 docker/getting-started
  • -d 以分离模式运行容器(在后台)
  • -p 80:80 将主机的 80 端口映射到容器中的 80 端口
  • docker/getting-started 要使用的镜像

1.2.什么是容器?

简而言之,容器是机器上的沙盒进程,与主机上的所有其他进程隔离。这种隔离利用了内核命名空间和 cgroups,这些特性在 Linux 中已经存在了很长时间。Docker 致力于使这些功能变得平易近人且易于使用。总而言之,一个容器:

  • 是镜像的可运行实例。可以使用 DockerAPI 或 CLI 创建、启动、停止、移动或删除容器。
  • 可以在本地机器、虚拟机上运行或部署到云端。
  • 可移植(可以在任何操作系统上运行)
  • 容器彼此隔离并运行自己的软件、二进制文件和配置。

1.3.什么是容器镜像?

运行容器时,它使用隔离的文件系统。此自定义文件系统由容器镜像提供。由于镜像包含容器的文件系统,它必须包含运行应用程序所需的一切——所有依赖项、配置、脚本、二进制文件等。镜像还包含容器的其他配置,例如环境变量、运行的默认命令、和其他元数据。

2.应用程序

2.1.新建

新建Dockerfile文件

构建容器镜像 docker build -t getting-started .

启动容器镜像 docker run -dp 3000:3000 getting-started

2.2.更新

获取容器id  docker ps

停止容器  docker stop <the-container-id>

删除容器  docker rm

启动更新容器镜像 docker run -dp 3000:3000 getting-started

2.2.共享

推送到Docker Hub   docker push docker/getting-started

登录Docker Hub  docker login -u YOUR-USER-NAME

指定镜像一个新名称 docker tag getting-started YOUR-USER-NAME/getting-started

再次推送到Docker Hub   docker push docker/getting-started

3.持久化数据库

Docker 维护磁盘上的物理位置。每次使用卷时,Docker 都会确保提供正确的数据。

# 1.创建卷
docker volume create todo-db
# 2.在仪表板(或使用 )中再次停止并删除待办事项应用程序容器 docker rm -f <id>,因为它仍在运行而不使用持久卷。
# 3.启动 todo 应用程序容器,但添加-v标志以指定卷安装。将使用命名卷并将其挂载到/etc/todos,这将捕获在该路径创建的所有文件。
docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
# 4.容器启动后,打开应用程序并将一些项目添加到待办事项列表中。
# 5.停止并删除 todo 应用程序的容器。使用仪表板或docker ps获取 ID,然后docker rm -f <id>将其删除。
# 6.使用上面的相同命令启动一个新容器。
# 7.打开应用程序。应该会看到您的项目仍在列表中!
# 完成检查列表后,继续删除容器。

# 查看卷
docker volume inspect todo-db

4.使用绑定挂载

使用绑定挂载,可以控制主机上的确切挂载点。可以使用它来持久化数据,但它通常用于向容器中提供额外的数据。在处理应用程序时,可以使用绑定挂载将源代码挂载到容器中,让它看到代码更改、响应,并让我们立即看到更改。

对于基于节点的应用程序,nodemon是监视文件更改然后重新启动应用程序的好工具。大多数其他语言和框架中都有等效的工具。

绑定挂载和命名卷是 Docker 引擎附带的两种主要卷类型。但是,可以使用其他卷驱动程序来支持其他用例(SFTPCephNetAppS3等)。

命名卷绑定挂载
Host位置Docker 选择自己控制
挂载示例 (using -v)my-volume:/usr/local/data/path/to/data:/usr/local/data
用容器内容填充新卷YesNo
支持卷驱动程序YesNo

4.1.启动一个开发模式容器

要运行我们的容器以支持开发工作流程,我们将执行以下操作:

  • 将源代码挂载到容器中
  • 安装所有依赖项,包括“dev”依赖项
  • 启动 nodemon 以监视文件系统更改
# 1.确保您没有getting-started运行任何以前的容器。
# 2.从应用程序目录运行以下命令。
docker run -dp 3000:3000 \
     -w /app -v "$(pwd):/app" \
     node:12-alpine \
     sh -c "yarn install && yarn run dev"
# -dp 3000:3000 和之前一样。以分离(后台)模式运行并创建端口映射
# -w /app 设置“工作目录”或命令将运行的当前目录
# -v "$(pwd):/app" 将容器中主机的当前目录绑定挂载到/app目录中
# node:12-alpine 要使用的镜像。请注意,这是来自 Dockerfile 的应用程序的基础镜像
# sh -c "yarn install && yarn run dev"- 命令。使用sh启动一个 shell 并运行yarn install以安装所有依赖项,然后运行yarn run dev​​. 如果查看package.json,会看到dev脚本正在启动nodemon。
# 查看日志docker logs。
docker logs -f <container-id>
# 看完日志后,按Ctrl+退出C。
# 现在,对应用程序进行更改。
# 随意进行任何其他更改。完成后,停止容器并使用以下命令构建新镜像
docker build -t getting-started .

5.多容器应用

5.1.容器网络

默认情况下,容器是独立运行的,对同一台机器上的其他进程或容器一无所知。如何让一个容器与另一个容器通信呢?答案是 网络

5.2.启动 MySQL

# 创建网络
docker network create todo-app
# 启动 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:5.7
# 要确认我们已启动并运行数据库,请连接到数据库并验证它是否已连接。
docker exec -it <mysql-container-id> mysql -u root -p

5.3.连接到 MySQL

为了解决通信问题,我们将使用nicolaka/netshoot容器,它附带了许多对故障排除或调试网络问题很有用的工具。

# 使用 nicolaka/netshoot 镜像启动一个新容器。确保将其连接到同一网络。
docker run -it --network todo-app nicolaka/netshoot
# 在容器内部,我们将使用dig命令,这是一个有用的 DNS 工具。我们将查找主机名的 IP 地址mysql。
dig mysql

todo 应用程序支持设置一些环境变量来指定 MySQL 连接设置。他们是:

  • MYSQL_HOST- 正在运行的 MySQL 服务器的主机名
  • MYSQL_USER- 用于连接的用户名
  • MYSQL_PASSWORD- 用于连接的密码
  • MYSQL_DB- 连接后使用的数据库

通过 Env Vars 设置连接设置

虽然使用 env vars 来设置连接设置对于开发来说通常是可以的,但 在生产中运行应用程序时,它是非常不受欢迎的。Docker 的前安全主管 Diogo Monica 写了一篇精彩的博客文章来 解释原因。

更安全的机制是使用容器编排框架提供的秘密支持。在大多数情况下,这些秘密作为文件挂载在正在运行的容器中。您会看到许多应用程序(包括 MySQL 映像和待办事项应用程序)也支持带有_FILE后缀的 env var,以指向包含变量的文件。

例如,设置MYSQL_PASSWORD_FILEvar 将导致应用程序使用引用文件的内容作为连接密码。Docker 没有做任何事情来支持这些环境变量。您的应用需要知道如何查找变量并获取文件内容。

# 注意:对于 MySQL 8.0 及更高版本,请确保在mysql
mysql> ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY 'secret';
mysql> flush privileges;
# 指定上面的每个环境变量,并将容器连接到应用程序网络。
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:12-alpine \
   sh -c "yarn install && yarn run dev"

# 查看容器 ( docker logs <container-id>) 的日志。
nodemon src/index.js
# 在浏览器中打开应用程序,然后将一些项目添加到待办事项列表中。
# 连接 mysql 数据库并证明项目正在写入数据库。记住,密码。
docker exec -it <mysql-container-id> mysql -p todos
mysql> select * from todo_items;

6.使用 Docker Compose

Docker Compose是一种用于帮助定义和共享多容器应用程序的工具。使用 Compose,可以创建一个 YAML 文件来定义服务,并且使用一个命令,可以启动所有内容或将其全部关闭。

使用 Compose的一优势是可以在文件中定义应用程序堆栈,将其保存在项目 repo 的根目录中(它现在是版本控制的),并且可以轻松地让其他人为您的项目做出贡献。

6.1.安装 Docker Compose 

如果为 Windows 或 Mac 安装了 Docker Desktop/Toolbox,那么已经拥有 Docker Compose!Play-with-Docker 实例也已经安装了 Docker Compose。如果在 Linux 机器上,则需要安装 Docker Compose

查看版本信息  docker-compose version

 6.2.创建 Compose 文件

1.在 app 项目的根目录下,创建一个名为docker-compose.yml.

2.在撰写文件中,将从定义模式版本开始。在大多数情况下,最好使用支持的最新版本。可以查看 当前架构版本和兼容性矩阵的Compose 文件参考。 

        version: "3.7"

3.定义我们希望作为应用程序的一部分运行的服务(或容器)列表。

        version: "3.7"
        services:

6.3.定义应用服务

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:12-alpine \
  sh -c "yarn install && yarn run dev"

1.首先,为容器定义服务入口和镜像。可以为服务选择任何名称。该名称将自动成为网络别名,这在定义 MySQL 服务时会很有用。

version: "3.7"

 services:
   app:
     image: node:12-alpine

2.通常,看到command接近image定义的内容,尽管没有要求。

version: "3.7"

 services:
   app:
     image: node:12-alpine
     command: sh -c "yarn install && yarn run dev"

3.通过定义服务来迁移-p 3000:3000命令的一部分ports。将在这里使用 短语法,但也有更详细 的长语法可用。

version: "3.7"

 services:
   app:
     image: node:12-alpine
     command: sh -c "yarn install && yarn run dev"
     ports:
       - 3000:3000

4.使用and定义迁移工作目录 ( -w /app) 和卷映射 ( )。Volumes 也有短句句。-v "$(pwd):/app"working_dirvolumes

Docker Compose 卷定义的一个优点是可以使用当前目录的相对路径。

version: "3.7"

 services:
   app:
     image: node:12-alpine
     command: sh -c "yarn install && yarn run dev"
     ports:
       - 3000:3000
     working_dir: /app
     volumes:
       - ./:/app

5.最后,使用environment密钥迁移环境变量定义。

version: "3.7"

 services:
   app:
     image: node:12-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

6.4.定义 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:5.7

1.首先定义新服务并为其命名,mysql以便它自动获取网络别名。指定要使用的镜像。

 version: "3.7"

 services:
   app:
     # The app service definition
   mysql:
     image: mysql:5.7

2.将定义卷映射。当使用 docker run 运行容器时,会自动创建命名卷。但是,在使用 Compose 运行时不会发生这种情况。需要在顶层 volumes:部分定义卷,然后在服务配置中指定挂载点。通过仅提供卷名,使用默认选项。不过,还有更多选择

version: "3.7"

 services:
   app:
     # The app service definition
   mysql:
     image: mysql:5.7
     volumes:
       - todo-mysql-data:/var/lib/mysql

 volumes:
   todo-mysql-data:

3.最后,需要指定环境变量

version: "3.7"

 services:
   app:
     # The app service definition
   mysql:
     image: mysql:5.7
     volumes:
       - todo-mysql-data:/var/lib/mysql
     environment:
       MYSQL_ROOT_PASSWORD: secret
       MYSQL_DATABASE: todos

 volumes:
   todo-mysql-data:

此时,完成docker-compose.yml

version: "3.7"

services:
  app:
    image: node:12-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:5.7
    volumes:
      - todo-mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: todos

volumes:
  todo-mysql-data:

6.5.运行应用程序

准备了docker-compose.yml文件,就可以启动它了!

1.确保没有其他 app/db 副本首先运行(docker psdocker rm -f <ids>)。

2.docker-compose up使用命令启动应用程序堆栈。将添加-d标志以在后台运行所有内容。

3.docker-compose logs -f 或 docker-compose logs -f app 使用命令查看日志。将看到每个服务的日志交错到一个流中。标志“-f”日志,因此会在生成时实时输出。

4.应该能够打开应用程序并看到它正在运行。

6.6.停止

docker-compose down

7.镜像构建最佳实践

7.1.安全扫描

docker scan

必须登录到 Docker Hub 才能扫描您的镜像。运行命令docker scan --login,然后使用 docker scan <image-name>.

扫描具体镜像

docker scan getting-started

7.2.镜像分层

docker image history --no-trunc APP
# --no-trunc 完整输出

7.3.图层缓存

Dockerfile

# syntax=docker/dockerfile:1
FROM node:12-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]

回到镜像历史输出, Dockerfile 中的每个命令都成为镜像中的一个新层。当镜像更改时,必须重新安装 yarn 依赖项。有没有办法来解决这个问题?每次构建时都发布相同的依赖项没有多大意义,对吧?

为了解决这个问题,需要重新构建我们的 Dockerfile 以帮助支持依赖项的缓存。对于基于节点的应用程序,这些依赖项在package.json文件中定义。那么,如果首先只复制该文件,安装依赖项,然后复制其他所有内容怎么办?

1.更新 Dockerfile 以package.json首先复制,安装依赖项,然后复制其他所有内容。

# syntax=docker/dockerfile:1
 FROM node:12-alpine
 WORKDIR /app
 COPY package.json yarn.lock ./
 RUN yarn install --production
 COPY . .
 CMD ["node", "src/index.js"]

2..dockerignore使用以下内容在与 Dockerfile 相同的文件夹中创建一个文件。

node_modules

.dockerignore文件是一种有选择地仅复制镜像相关文件的简单方法。在此处阅读有关此内容的更多信息 。在这种情况下,node_modules应在COPY第二步中省略该文件夹,否则可能会覆盖由该RUN步骤中的命令创建的文件。有关为何建议将其用于 Node.js 应用程序和其他最佳实践的更多详细信息,请查看关于 Dockerizing a Node.js Web 应用程序的指南。 

3.使用docker build.

 docker build -t getting-started .

4.对src/static/index.html文件进行更改。

5.docker build -t getting-started .现在再次使用构建 Docker 映像。

7.4.多阶段构建

多阶段构建是一个非常强大的工具,可以帮助使用多个阶段来创建图像。它们有几个优点:

  • 将构建时依赖项与运行时依赖项分开
  • 通过仅运送您的应用程序需要运行的内容来减小整体图像大小

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐