Docker 使用指南

1,846 阅读21分钟

一、 什么是 Docker

Docker 是一个开源的引擎(核心程序), 可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器(将安装部署的代码、组件、依赖、配置环境等集成在一个独立的环境), 开发者在本地编译测试通过的容器可以批量地在生产环境中进行部署

1.1 镜像、容器、仓库的概念

镜像:

  1. Docker 镜像(Image)类比于我们操作系统的镜像, 本质上它就是一个只读的模板
  2. 镜像可以用来创建 Docker 容器, 容器可以类比为我们的操作系统
  3. 一个镜像可以创建多个容器, 就好像操作系统的镜像可以在任意设备上进行安装

容器:

  1. 可以把容器看做是一个具有最基础的 Linux 环境(包括 root 用户权限、进程空间、用户空间和网络空间等等)而这个容器同时又把应用运行时所需的外部环境、内部代码、组件、依赖打包放进容器, 容器内自成一个独立的环境于外部隔离, 应用发布以容器为单位, 只要有需要就可以处处部署
  2. 如果把容器类比为装载货物的集装箱、那么应用所需的依赖、环境... 就类似杂乱的货物, 将所有杂乱的货物封装在对应的集装箱内, 那么在货物的运输、转移等过程中少了搬运、分类等一系列成本
  3. 容器是镜像创建运行的一个实例, 容器允许被启动、停止、删除, 每个容器都是相互隔离的、保证安全的平台

仓库:

  1. 仓库(Repository)是集中存放镜像文件的场所(镜像的托管平台)
  2. 仓库分为公开仓库(Public)和私有仓库(Private)两种形式

1.2 运行容器流程

如图: 执行 docker run 运行一个容器需要指定一个镜像, 在创建容器前会先从本地查找是否有对应的镜像, 如果没有则从远程仓库进行拉取(下载)镜像, 然后创建容器并运行

1.3 Docker 的优势

  1. 资源独立、隔离: Docker 通过 Linux namespace, cgroup 限制了硬件资源与软件运行环境, 与宿主机上的其他应用实现了隔离, 做到了互不影响
  2. 环境的一致性: 将应用所需的相关环境、依赖、代码等等集成到独立的空间内, 使得和外部环境进行了隔离, 从而保证每一次部署容器环境的一致性
  3. 轻量化: 传统虚拟机技术(VM)是虚拟出一套硬件后, 在其上运行一个完整操作系统, 在该系统上再运行所需应用进程(占用资源多, 启动慢), Docker 容器内的应用进程则直接运行于宿主的内核, 容器内没有自己的内核, 而且也没有进行硬件虚拟,因此容器要比传统虚拟机更为轻便, 也使得 Docker 能够更高效的利用系统资源
  4. 更轻松的迁移和扩展: 将应用容器化使得应用的部署变得简单、更容易进行项目的移植, 同时多个容器容器间又可相互组合扩展

二、 Ubuntu 下 Docker 的安装与配置

2.1 Docker 的安装

参考: 官方文档

# 1. 卸载旧版本
$ sudo apt-get remove docker docker-engine docker.io containerd runc

# 2. 更新软件包
$ sudo apt-get update

# 2. 安装所需依赖
$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

# 3. 添加Docker的官方GPG密钥:
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88

# 4. 添加存储库
$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

# 5. 更新软件包
$ sudo apt-get update

# 6. 安装 docker
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

2.2 配置镜像源(仓库)

这里可以选择任意的国内镜像源, 下面以阿里容器镜像服务 为例, 登录 阿里容器镜像服务 根据下图指示复制加速器地址

修改配置并重启服务:

# 编辑配置文件
$ sudo vim /etc/docker/daemon.json

# 添加如下内容
{
  "registry-mirrors": ["加速器地址"]
}

# 保存并重启服务
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

三、 Docker 启停以及帮助命令

3.1 Docker 服务启停

  • 开启 Docker 服务: sudo service docker start
  • 重启 Docker 服务: sudo service docker restart
  • 关闭 Docker 服务: sudo service docker stop
  • 守护进程重启: sudo systemctl daemon-reload

3.2 Docker 相关帮助命令

说明: Docker 系统有两个程序: Docker 服务端和 Docker 客户端。其中 Docker 服务端是一个服务进程, 管理着所有的容器, Docker 客户端则扮演着 Docker 服务端的远程控制器, 可以用来控制 Docker 的服务端进程。大部分情况下, Docker 服务端和客户端运行在一台机器上。

  • 查看 Docker 版本信息: sudo docker version
  • 查看 Docker 信息: sudo docker info
  • 查看 Docker 帮助信息: sudo docker --help

四、 Docker 针对镜像常用操作

4.1 远程仓库镜像搜索

格式: docker search [可选选项] <搜索词条>

# 查询和 ubuntu 相关的镜像, --limit 指定显示的最大条数
$ sudo docker search --limit 30 mongo

4.2 从远程拉取镜像

格式: docker pull <镜像的仓库源>:<指定标签>

# 拉取镜像名为 mongo 标签名为 4.0 的镜像
$ sudo docker pull mongo:4.0

# 未指定标签则拉取标签为 latest 的镜像
$ sudo docker pull mongo

4.3 查询本地已有的镜像

格式: docker images

$ sudo docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mongo               latest              1c7e513b19f3        8 hours ago         361MB
mongo               4.0                 1bc58f3232ec        4 days ago          413MB

各个选项说明:

  • REPOSITORY:表示镜像的仓库源
  • TAG:镜像的标签
  • IMAGE ID:镜像ID
  • CREATED:镜像创建时间
  • SIZE:镜像大小

补充说明: 镜像的 ID 唯一标识了镜像, TAG 信息用来标记来自同一个仓库的不同镜像, 通过 TAG 信息来区分发行版本。

4.4 镜像的导出

格式: docker save -o <存储路径> <指定镜像>

# 将指定 ID 的镜像导出为 Company/mongo.tar
$ sudo docker save -o Company/mongo.tar 1c7e513b19f3

# 将 mongo:4.0 镜像导出到为 Company/mongo.tar
$ sudo docker save -o Company/mongo1.tar mongo:4.0

4.5 镜像的导入

格式: docker load --input <本地tar包>

# 将 Company/mongo.tar 导入为本地镜像
$ sudo docker load --input ./Company/mongo.tar

4.6 镜像的删除

格式: sudo docker rmi <要删除的镜像>

# 删除指定 ID 的镜像
$ sudo docker rmi 1c7e513b19f3

# 删除  mongo:4.0 镜像
$ sudo docker rmi mongo:4.0

# 删除所有的镜像: docker images 查询所有镜像 -q 表示只列出镜像的 ID, 然后所有 ID 传递给 rm 命令
$ docker rmi $(docker images -q)

4.7 修改镜像仓库源、标签

格式: docker tag [原仓库源]:[原标签] [新仓库源]:[新标签]

# 修改 mongo:latest 为 mongo2:5.0
$ sudo docker tag mongo:latest mongo2:5.0

# 重新查询本地镜像会发现实际是重新创建了一个引用, 他们具有相同的镜像 ID
$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mongo               latest              1c7e513b19f3        8 hours ago         361MB
mongo2              5.0                 1c7e513b19f3        8 hours ago         361MB

五、 Docker 针对容器常用操作

5.1 查看本地已有容器

格式: docker ps [可选参数]

# 查看本地正在运行的容器
$ sudo docker ps

# 查看本地所有容器
$ sudo docker ps -a

5.2 基于指定镜像启动(创建)一个容器

格式: docker run [指定镜像] [可选项]

5.2.1 通过镜像创建容器, 并在创建容器后在容器中执行给定命令

# 通过 ID 指定一个镜像, 并基于该镜像创建一个容器
# 创建容器后会在容器中执行 `echo "Hello world"` 命令执行结果将回显在本地终端
$ sudo docker run 3556258649b2 echo "Hello world"

5.2.2 通过镜像创建容器, 并开启一个虚拟终端进行交互

补充: 可通过 exit 或者 ctrl+P+Q 退出虚拟终端

# 通过 ID 指定一个镜像, 并基于该镜像创建一个容器
# 同时打开虚拟终端与容器进行交互, 姑且理解为 ssh 到容器中
$ sudo docker run -i -t 3556258649b2
root@a0de10bc49e8:/#

上面命令选项说明:

  1. -i:以交互模式运行容器, 通常与 -t 同时使用
  2. -t:为容器分配一个伪输入终端, 通常与 -i 同时使用

5.2.3 通过镜像创建容器, 如何让一个容器每次运行时都在后台执行

前置知识: 在创建镜像时可以根据 CMD 指定启动容器时需要运行的命令、程序, 如果镜像通过 CMD 指定了一个自身持续运行的程序那么我们只需要通过 -d 即可让容器在后台运行, 否则可以通过 -d -t 选项让容器开启一个终端并在后台执行, 使得容器实现后台执行的目的;

# 1. mongo 因镜像通过 CMD 指定可一个持续运行的容器, 所以只需使用 -d 即可让容器在后台执行
$ sudo docker run -d mongo:4.0 # 可以通过 docker ps 查看容器的运行情况

# 2. ubuntu 因镜像未通过 CMD 指定可一个持续运行的容器, 所以需使用 -d -t 才能让容器在后台执行
$ sudo docker run -d -t ubuntu:latest  # 可以通过 docker ps 查看容器的运行情况

上面命令选项说明:

  1. -d:后台运行容器
  2. -t:为容器重新分配一个伪输入终端

5.2.4 通过镜像创建 mongo 容器, 实现容器的命名、挂载卷、端口映射

# 执行下面命令后可通过 mongo GUI 工具通过 localhost:27017 连接至容器内 mongo 数据库
$ sudo docker run \
    -d \
    --name blog-mongo \
    -e "TZ=Asia/Shanghai" \
    -v /home/store/blog/mongo/db:/data/db \
    -v /home/store/blog/mongo/configdb:/data/configdb \
    -p 27017:27017 \
    mongo:4.0

上面命令选项说明:

  1. \ 可以实现终端上的换行, 这里只是为了方便展示
  2. --name: 为容器指定名称
  3. -e: 为容器设置环境变量
  4. -d: 每次容器启动时都在后台执行
  5. -v: 将容器内部目录或文件挂载到本地(可以简单理解为共享目录), 格式 -v 本地绝对目录:容器绝对目录
  6. -p: 将本地端口和容器内指定公开端口进行映射, 之后访问本地端口即可访问到容器内部, 格式: -p 本地端口: 容器公开端口

补充说明:

  1. 如果需要设置多个挂载卷则可以使用多个 -v 选项, -e -p 同理
  2. -v 设置挂载卷有点类似共享文件夹, 将配置文件挂载到本地可以方便配置, 将数据库数据目录挂载到本地, 方便在容器版本升级时避免数据丢失等问题, 当然在 window 下设置挂载卷可能会有各种权限问题, 这时如果非必须可以放弃目录的挂载
  3. -p 对应还有 -P 选项, 该选项会将容器内所有公开的端口随机映射到本地上

5.3 重命名一个容器

格式: docker rename [原容器名称] [新容器名称]

# 将 mongo 容器重命名为 blog_mongo
$ sudo docker rename mongo blog_mongo

5.3 容器的启停

格式: docker 命令 [容器ID] 对应的命令有: start(启动)、 restart(重启)、 stop(停止)、 kill(杀死)

# 停止容器, 先结束容器内部进程后关闭容器
$ sudo docker stop 2660c7e2163c

# 开启容器
$ sudo docker start 2660c7e2163c

# 重启容器
$ sudo docker restart 2660c7e2163c

# 杀死容器, 不一一结束容器内部进程 直接关闭容器
$ sudo docker kill 2660c7e2163c

5.4 容器的删除

格式: docker rm [容器ID]

# 删除指定容器, 正在运行的容器无法删除
$ sudo docker rm cd428596c500

# 通过 -f 选项强制删除指定容器, 正在运行的容器也会被删除
$ sudo docker rm -f cd428596c500

# 强制删除所有容器, docker ps -a -q 查所有容器并将容器 ID 传给 rm
$ sudo docker rm -f $(sudo docker ps -a -q)

5.5 在正在运行的容器中运行命令

格式: docker exec [可选项] [容器ID] [待执行命令]

5.5.1 通过容器执行 echo "hello world"

# 通过 ID 指定容器并在容器内执行 echo "hello world" 执行结果将在本地终端回显
$ sudo docker exec 2660c7e2163c echo "hello world"

# 通过 -d 选项, 将在后台执行命令
$ sudo docker exec -d 2660c7e2163c echo "hello world"

5.5.2 为正在运行的容器打开一个虚拟终端

# 启动一个 bash 终端, 并许用户进行交互,可通过 exit 或者 ctrl+P+Q 退出虚拟终端
$ sudo docker exec -i -t 2660c7e2163c bash

5.5.3 通过 -e 选项为正在运行的容器设置环境变量

# 启动一个 bash 终端, 为容器设置环境变量
$ sudo docker exec -e="TZ=Asia/Shanghai" 2660c7e2163c bash

5.6 本地和正运行中的容器相互拷贝数据

格式: docker cp [将要被拷贝的文件] [存放位置]

  • 拷贝本地数据到容器内部: docker cp 本地主机路径 容器ID:容器内绝对路径
# 拷贝当前目录下 config.json 文件到容器 2660c7e2163c /home 目录下
$ sudo docker cp ./config.json 2660c7e2163c:/home
  • 拷贝容器内数据到本地: docker cp 容器ID:容器内绝对路径 目的主机路径
# 拷贝容器 2660c7e2163c /home/config.json 到本地当前目录下
$ sudo docker cp 2660c7e2163c:/home/config.json .

5.7 查看容器日志

格式: docker logs [选项] [容器ID]

$ sudo docker logs e5251f3de480

5.8 查看容器内运行的进程

格式: docker top [选项] [容器ID]

$ sudo docker top e5251f3de480

六、 镜像的拉取、修改、发布演示

这里以阿里容器镜像服务为例

  • 如果未设置登录凭证则先进行设置

# 拉取 ubuntu 镜像
$ sudo docker pull ubuntu
  • 运行容器并开启虚拟终端
# 运行容器并开启虚拟终端
$ sudo docker run -it ubuntu:latest
  • 修改容器内容: 安装 vim
# 更新软件包
$ apt-get update
# 安装 vim
$ apt-get install vim
  • 查看上文创建的镜像仓库信息并复制镜像仓库源: 镜像仓库列表 --> 点击管理

  • 提交修改: docker commit

格式: docker commit -m [提交信息] [容器] [镜像仓库源]:[标签]

# 1. 提交本地容器修改, 将在本地生成新的镜像
$ sudo docker commit -m '安装 vim' 5ba3316db8d9 registry.cn-beijing.aliyuncs.com/qianyin/vim-ubuntu:1.0

# 2. 查看本地镜像
$ sudo docker images
REPOSITORY                                            TAG                 IMAGE ID            CREATED             SIZE
registry.cn-beijing.aliyuncs.com/qianyin/vim-ubuntu   1.0                 5f6963d18bd3        9 seconds ago       91.1MB
ubuntu                                                latest              a2a15febcdf3        3 hours ago         64.2MB
  • 登录阿里 Docker Registry, 登录方法查看镜像仓库管理页面内的操作指南

  • 上传本地镜像到远程仓库: docker push

格式: docker push [镜像]

$ sudo docker push registry.cn-beijing.aliyuncs.com/qianyin/vim-ubuntu:1.0

七、 Docker file 生成镜像

7.1 Dockerfile 基本结构

dockerfile 基本结构由四部分组成:

  1. 基础镜像
  2. 维护者信息: 指定维护者信息
  3. 创建镜像时需要执行的命令
  4. 容器每次启动时需要执行的命令
  • 简单例子: 新建文件 docker/dockerfile 并添加下面内容
# 1. 基础镜像: 表示在 ubuntu 镜像基础上进行扩展
FROM ubuntu

# 2. 维护者信息: 填写维护者的信息
MAINTAINER qianyin qianyin95@gmai.com

# 3. 镜像操作指令: 对镜像进行扩展, 安装 vim 工具
RUN apt-get update && apt-get install -y vim

# 4. 容器启动时执行指令: 指定新建容器在每次运行时需要执行的命令
CMD bash
  • 通过 docker build 创建镜像

格式: docker build [选项] [目录]

注意: docker build 命令后面跟着是一个目录, 该命令指定 build 命令的上下文环境, 该命令会在该目录下查找所有 dockerfile 来构建镜像(也包括子目录下的 dockerfile 文件)

# -t 指定构建出镜像的 [仓库源]:[标签]
$ sudo docker build -t vim-ubuntu:1.0 ./docker

# 构建完运行容器并执行 vim --help 将会显示 vim 的帮助信息
$ sudo docker run vim-ubuntu:1.0 vim --help
  • 猜测 dockerfile 构建项目的步骤
  1. 运行基础镜像容器(本地没有则会进行拉取), 拉取的镜像将被缓存到本地如果不需要缓存至本地可以使用 --no-cache 参数
  2. 对运行的容器进行修改: docker file 中每一行指令则都会对容器进行一次修改, 而每次修改都会进行一次 commit
  3. 执行完所有指令后删除多余的临时镜像和容器, 完成镜像的构建

7.2 Dockerfile 指令介绍

指令格式: 指令 指令参数 切记在 dockerFile 中如果是字符串请记得使用 "" 而不要使用 ''

7.2.1 FORM: 指定基础镜像

格式: FORM [仓库源]:[标签]

  1. docker file 第一条指令必须为 FROM 指令
  2. 如果在同一个 Dockerfile 中要同时创建多个镜像时, 可以使用多个 FROM 指令(每个镜像一次)。
# 默认拉取 latest 镜像
FORM ubuntu

# 指定具体的基础镜像
FORM ubuntu:18.0

7.2.2 MAINTAINER: 指定维护者信息

格式: MAINTAINER [维护者信息]

MAINTAINER qianyin qianyin925@gmail.com

7.2.3 RUN: 构建镜像时需要运行的脚本命令

每条 RUN 指令将在当前镜像基础上执行指定命令, 并提交新的镜像。当命令较长时可以使用 \ 来换行。

  • 格式一: RUN [可执行命令]

将在 shell 终端中运行命令, 即使用 /bin/sh -c 执行命令

RUN apt-get update
  • 格式二: RUN [可执行文件, ...指定参数列表]

将使用 exec 执行命令, 记住命令参数都是字符串, 并且不能使用单引号 ''

# 指定终端来执行命令
RUN ["/bin/bash", "-c", "apt-get", "update"]

# 执行 ls 命令
RUN ["ls", "-a", "./home"]

7.2.4 CMD: 配置每次容器启动时需要执行的命令

配置每次容器启动时需要执行的命令, 每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条命令, 只有最后一条会被执行。同时如果用户创建容器时候指定了运行的命令, 则会覆盖掉 CMD 指定的命令。

  • 格式一: CMD [可执行命令]

将在 shell 终端中运行命令, 即使用 /bin/sh -c 执行命令

CMD apt-get update
  • 格式二: CMD [可执行命令, 指定参数, 指定参数]

将使用 exec 执行命令, 记住命令参数都是字符串, 并且不能使用单引号 ''

# 指定终端来执行命令
CMD ["/bin/bash", "-c", "apt-get", "update"]

# 执行 ls 命令
CMD ["ls", "-a", "./home"]

格式三: CMD [指定参数, 指定参数]

设置 ENTRYPOINT 指令所需要接收的参数

# CMD 作为 ENTRYPOINT 指令的参数
CMD ["-c", "bash"]
  • 同时执行多条命名的方式
# 直接通过 sh -c 执行脚本
CMD sh -c "cron && mongod --bind_ip_all"

7.2.5 ENTRYPOINT: 配置每次容器启动后需要执行的命令

配置每次容器启动后需要执行的命令, 并且不可被 docker run 提供的参数覆盖, 每个 dockerfile 中只能有一个 ENTRYPOINT, 当指定多个时, 只有最后一个起效。

  • 格式一: ENTRYPOINT [可执行命令]

将在 shell 终端中运行命令, 即使用 /bin/sh -c 执行命令

ENTRYPOINT apt-get update
  • 格式二: ENTRYPOINT [可执行文件, ...指定参数列表]

将使用 exec 执行命令, 记住命令参数都是字符串, 并且不能使用单引号 ''

# 指定终端来执行命令
ENTRYPOINT ["/bin/bash", "-c", "apt-get", "update"]

# 执行 ls 命令
ENTRYPOINT ["ls", "-a", "./home"]

7.2.6 ENV: 配置容器内环境变量

指定一个环境变量, 会被后续 RUN 指令使用, 并在容器运行时保留该环境变量

格式为: ENV [键] [值]

ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

7.2.7 EXPOSE: 容器向外暴露指定端口号

配置容器向外面暴露的端口号, 供互联系统使用。在启动容器时可以通过 -p 或者 -P 将端口映射到本地

格式: EXPOSE [...端口号列表]

# 暴露单个端口号
EXPOSE 1194/udp
EXPOSE 8080

# 暴露多个端口号
EXPOSE [1194/udp, 27017, 8080]

7.2.8 VOLUME: 设置容器允许被挂载的目录或文件

该命令创建一个可以从本地主机或其他容器挂载的挂载点, 一般用来存放数据库和需要保持的数据等

格式为: VOLUME [...路径列表]

VOLUME ["/etc/openvpn"]

7.2.9 ADD: 往容器添加文件

该命令将根据路径将指定文件复制到容器中中指定位置, 其中源路径可以是 Dockerfile 所在目录的一个相对路径, 也可以是一个 URL, 还可以是一个 tar 文件(将自动解压为目录)

格式为: ADD [源路径] [目标路径]

# 创建镜像时会将当前目录下 ./bin 添加到容器 /usr/local/bin
ADD ./bin /usr/local/bin

7.2.10 COPY: 往容器拷贝本地文件

该命令将复制本地文件至容器, 和 ADD 指定不同 COPY 源路径只能是本地路径不能是 URL, 当使用本地目录为源目录时, 推荐使用 COPY

格式为: COPY [源路径] [目标路径]

# 创建镜像时将拷贝当前目录下 ./bin 添加到容器 /usr/local/bin
COPY ./bin /usr/local/bin

7.2.11 USER: 指定运行容器时的用户

指定运行容器时的用户名或 UID, 后续的 RUN 也会使用指定用户, 当服务不需要管理员权限时, 可以通过该命令指定运行用户。并且可以在之前创建所需要的用户, 例如:RUN groupadd -r postgres && useradd -r -g postgres postgres。要临时获取管理员权限可以使用 gosu, 而不推荐 sudo

格式为: USER [用户名或 UID]

USER root

7.2.12 WORKDIR: 为容器配置工作目录

为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录, 可以使用多个 WORKDIR 指令, 后续命令如果参数是相对路径, 则会基于之前命令指定的路径

格式为: WORKDIR [工作目录路径]

WORKDIR /home
WORKDIR web
WORKDIR app
# 下面命令将输出: /home/web/app
RUN pwd

7.2.13 ONBUILD: 设置当所创建的镜像被作为基础镜像时需要执行的命令

设置当所创建的镜像被作为基础镜像时需要执行的命令

格式为 ONBUILD [DockerFile 指令]

ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src

八、 docker-compose

当项目同时需要维护多个 docker 容器时那么整个项目的维护管理就变得复杂了, 这时就可以使用 docker-compose 并通过一个 YAML 配置文件来管理维护多个容器的 Docker 应用程序, 该配置文件可配置每个容器启动时的参数、多个容器间的关联、依赖等等, 并可通过一条命令对多个容器进行启停...

8.1 docker-compose 模板文件常用配置

8.1.1 version: 指定版本

该字段指定当前配置文件所使用语法的版本号, 特别注意该字段值必须加 ""

version: "2"

8.1.2 services.image: 设置镜像

首先 services 分组用于定义当前项目下所有的服务相关配置, services.image 则定义创建当前服务对应容器所使用的镜像

# 定义版本号
version: "2"
# 配置当前项目下所有服务
services:
  # 当前服务名称(自定义)
  web:  
    # 指定当前创建当前服务对应容器所使用的镜像为 nginx
    image: nginx

8.1.3 services.build: 指定 build 上下文

和 services.image 字段不同的是该字段表示通过 dockerfile 创建当前服务对应的容器, 并指定上下文, 同时在同一服务中 services.image 和 services.build 不能共存

version: "2"
services:
  web:
    # 指定 dockerfile 所在目录
    build: ./docker-compse/dockerfile

8.1.4 services.container_name: 设置容器名

指定当前服务对应容器的名称

version: "2"
services:
  web:
    build: ./docker-compse/dockerfile
    # 指定当前服务对应容器的名称
    container_name: blog-web

8.1.5 services.volumes: 设置容器挂载卷

配置当前服务对应容器需要挂载的数据卷

version: "2"
services:
  web:
    build: ./docker-compse/dockerfile
    volumes:                           # 格式: 本地绝对路径或相对路径:容器内部绝对路径
      - /var/lib/mysql                 # 只是指定一个路径, 将会自动在创建一个相同路径的数据卷(这个路径是容器内部的)
      - /opt/data:/var/lib/mysql       # 使用绝对路径挂载数据卷
      - ./cache:/tmp/cache             # 以配置文件为中心的相对路径作为数据卷挂载到容器
      - ~/configs:/etc/configs/:ro     # 使用用户的相对路径(~/ 表示的目录是 /home/<用户目录>/ 或者 /root/

8.1.6 services.ports: 设置容器端口映射

配置当前服务对应容器和本地的端口映射关系

version: "2"
services:
  web:
    build: ./docker-compse/dockerfile
    ports:
      - 8080        # 本地将随机分配一个端口与容器内 8080 端口进行映射
      - 1008:27017  # 本地端口 1008 于容器内 27017 端口进行映射

8.1.7 services.expose: 为连接的服务暴露端口

将服务内对应容器的端口暴露给其所连接的服务, 而不暴露给宿主机, 只允许被连接的服务访问, 本地无法访问

version: "2"
services:
  web:
    build: ./docker-compse/dockerfile
    expose:
      - 3000  # 将容器内 3000 端口暴露给被连接的服务
      - 8000  # 将容器内 8000 端口暴露给被连接的服务

8.1.8 services.link: 设置要连接的服务

设置当前服务所需连接到哪些服务, 在当前服务内可通过服务名访问其他服务

version: "2"
services:
  web:
    build: ./docker-compse/dockerfile
    links:
      - db          # 连接到 db, 可使用 db 作为 hostname 访问 db 服务
      - db:database # 连接到 db, 并设置别名 database, 可以使用 database 作为 hostname 访问 db 服务

8.1.9 services.depends_on: 设置当前服务所依赖的服务

设置当前服务依赖于哪些服务, 在这些服务启动后才启动当前服务

version: "2"
services:
  web:
    build: ./docker-compse/dockerfile
    depends_on: # 在 redis 和 lb 服务启动后才会启动当前服务
      - redis
      - lb

8.1.10 services.command: 设置容器启动时执行的命令

设置当前服务对应容器启动时所需要执行的命令

version: "2"
services:
  web:
    build: ./docker-compse/dockerfile
    command: npm run start # 容器启动时将执行 npm run start
  • 补充: 同时执行多条命令
version: "2"
services:
  web:
    build: ./docker-compse/dockerfile
    command:
      - /bin/sh
      - -c
      - |
        # 在这儿可以编写你的 shell 脚本
        pm2 start ecosystem.config.js && pm2 logs

8.1.11 services.entrypoint: 设置容器启动后执行的命令

设置服务对应容器启动后需要执行的命令, 覆盖 Dockerfile 中的定义的 entrypoint

version: "2"
services:
  web:
    build: ./docker-compse/dockerfile
    entrypoint: /code/entrypoint.sh

8.1.12 services.environment: 设置容器的环境变量

为当前服务对应容器添加环境变量

version: "2"
services:
  web:
    build: ./docker-compse/dockerfile
    environment:
      - RACK_ENV=development
      - SHOW=ture

8.1.13 services.env_file: 以文件形式设置容器的环境变量

通过文件的形式为当前服务对应容器添加环境变量, 和 environment 冲突则已 environment 为主

version: "2"
services:
  web:
    build: ./docker-compse/dockerfile
    env_file:
      - ./common.env      # 使用相对路径
      - /opt/secrets.env  # 使用绝对路径

8.1.14 services.logging: 配置日志

为当前服务配置日志, driver 指定日志驱动类型 options 则配置日志驱动的相关参数

version: "2"
services:
  web:
    build: ./docker-compse/dockerfile
    logging: # 配置日志
      driver: "json-file"  # 指定日志驱动类型
      options:             # 配置日志驱动的相关参数
        max-size: "100k"   # 文件大小限制
        max-file: "20"     # 文件数据限制

8.2 docker-compose 常用命令

下列所有相关命令都允许在命令最后添加服务名, 针对单个服务进行操作

8.2.1 构建项目并运行项目

# -d 表示在后台运行项目
$ docker-compose up -d

8.2.1 查看当前项目相关容器

$ docker-compose ps

8.2.1 运行项目

$ docker-compose start

8.2.1 停止项目

$ docker-compose stop

8.2.1 重启项目

$ docker-compose restart

8.2.1 查看日志

# -f 表示查看实时日志
$ docker-compose logs -f

九、 补充 && 应用

9.1 通过 docker 快速搭建 Nginx 服务

9.1.1 复制 nginx 相关配置

  1. 在当前项目下创建 conf 目录用于挂载 nginx 配置文件
  2. 创建临时容器并拷贝默认配置文件至本地 ./conf/nginx.conf
  3. 删除临时容器
$ sudo mkdir conf && \
  sudo docker cp $(sudo docker run -d --name tem-nginx nginx):/etc/nginx/nginx.conf ./conf/nginx.conf && \
  sudo docker rm -f tem-nginx

9.1.2 运行容器

  1. 将本地 8081 和容器内 80 端口进行映射
  2. 将容器内 html logs 目录和当前目录下 html logs 进行挂载(目录不存在将自动创建)
  3. 将容器内 nginx 配置文件和当前目录下 ./conf/nginx.conf 进行挂载
  4. 设置 conf html logs 目录的权限
$ sudo docker run -d -p 8081:80 \
    --name nginx-web-6666 \
    -v $PWD/html:/usr/share/nginx/html \
    -v $PWD/conf/nginx.conf:/etc/nginx/nginx.conf \
    -v $PWD/logs:/var/log/nginx nginx && \
  sudo chmod -R 777 conf html logs

9.2 docker-compose 简单实例

9.2.1 docker-compose.yml 配置

  1. 配置中定义三个服务 mongo、node、web
  2. node 服务连接到 mongo 服务
  3. mongo 服务暴露出 27017 端口给 node 服务
  4. 在 node 服务中可通过 mongo:27017 访问 mongo 服务
version: '2'
services:
  mongo:
    image: mongo                  # 指定镜像
    container_name: blog-mongo    # 指定容器名称
    expose:                       # 暴露容器端口给连接到当前服务的设备
      - 27017
    volumes:                      # 设置容器的挂载卷
      - ./store/mongo/db:/data/db
      - ./store/mongo/configdb:/data/configdb
    logging:                      # 设置服务的日志
      driver: "json-file"
      options:
        max-size: "100k"
        max-file: "20"
  node:
    build: ./                    # 指定 build 上下文
    container_name: blog-service # 指定容器名称
    ports:                       # 设置容器和本地的端口映射关系
      - 4000:4000
    links:                       # 连接到 mongo 服务可通过 mongo:27017 访问服务
      - mongo
    environment:                 # 设置容器的环境变量
      - NODE_ENV=production
    depends_on:                  # 设置当前服务所依赖的服务, 先启动 mongo 再启动当前服务
      - mongo
    command:                     # 设置启动容器时需要执行的命令
      - /bin/sh
      - -c
      - |
        pm2 start ecosystem.config.js && pm2 logs
    volumes:                     # 设置容器的挂载卷
      - ../:/var/service
    logging:                     # 设置服务的日志
      driver: "json-file"
      options:
        max-size: "100k"
        max-file: "20"
  web:
    image: nginx                  # 指定镜像
    container_name: blog-web      # 指定容器名称
    ports:                        # 设置容器和本地的端口映射关系
      - 80:80
    depends_on:                   # 设置当前服务所依赖的服务, 先启动 node 再启动当前服务
      - node
    volumes:                      # 设置容器的挂载卷
      - ../html/build:/usr/share/nginx/html
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./store/nginx/logs/:/var/log/nginx
    logging:                      # 设置服务的日志
      driver: "json-file"
      options:
        max-size: "100k"
        max-file: "20"

9.2.2 dockerfile 内容

在镜像 node 的基础上添加 pm2 工具, 并设置工作目录

# 基础镜像: 表示在 node 镜像基础上进行扩展
FROM node

# 维护者信息: 填写维护者的信息
MAINTAINER qianyin qianyin95@gmai.com

# 镜像操作指令:
RUN npm config set registry https://registry.npm.taobao.org/ && \
    npm install pm2 -g && \
    mkdir /var/service

# 设置工作目录
WORKDIR /var/service

# 设置挂载点
VOLUME [/var/service]

# 对外暴露端口
EXPOSE 4000

# 容器启动时执行指令: 指定新建容器在每次运行时需要执行的命令
CMD /bin/bash

Group 3143