Docker 实践指北(下)

Author Avatar
我爱吃包子 4月 18, 2019

前言

本文将会介绍 docker 的基础知识,docker 的组成以及通过 docker 搭建一个服务,包括数据库、后端服务、前端服务。项目的源码 已经放到了我的的 github 上,详情可以点击下面链接。https://github.com/wangcheng007/blog

本来想一篇文章描述下的,发现一篇文章篇幅太长,这篇文章介绍通过 Dockerfile 创建镜像以及通过 docker-compose 来管理容器,上篇文章简单的介绍 Docker 的一些知识和一些常用命令。

通过 Dockerfile 创建镜像

Dockerfile 是 Docker 特有的镜像构建定义文件,通过了解他,你能真正体验一种进行秒级镜像迁移的乐趣。

关于 Dockerfile

Dockerfile 是 Docker 中用于定义镜像自动化构建流程的配置文件,在 Dockerfile 中,包含了构建镜像过程中需要执行的命令和其他操作。通过来书,我们对 Dockerfile 的定义就是针对一个名为 Dockerfile 的文件,本质是一个文本文件。Dockerfile 的内容很简单,主要是两种形式,一种是注释行,一种是指令行。

1
2
# 获取一个镜像
FROM node:10-alpine
编写 Dockerfile 文件

首先我们看一个完整 Dockerfile 的例子,这是我上面写的实例基于 node 10 基础镜像而生成的一个新的对象,用于将服务文件复制进镜像中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
FROM node:10-alpine

# create app directory
WORKDIR /usr/blog/server

# install
COPY server/package.json ./

RUN npm config set registry https://registry.npm.taobao.org && \
npm install && \
npm cache clean --force

COPY server .

EXPOSE 3000

CMD npm run dev

总体来说,我们可以将 Dockerfile 理解成一个由上而下执行的脚本文件。我们使用命令运行 Dockerfile 文件时,他会逐步执行我们编写的指令。编写一个 Dockerfile 我们只需要知道几个常见的指令就可以轻松完成。

常见 Dockerfile 指令

和上一篇 Docker 的常用指令一样,想要详细的了解的可以点击这个链接查看我的学习笔记或者去官网查询。

指令 介绍 示例
FROM 选择一个已存在的镜像作为基础镜像 FROM
RUN 用于向控制台发送命令的指令 RUN [“executable”, “param1”, “param2”]
ENTRYPOINT 基于镜像启动容器的时候执行的命令 ENTRYPOINT command param1 param2
CMD 基于镜像启动容器的时候执行的命令,ENTRYPOINT指令会将 CMD 指令内容作为参数 CMD command param1 param2
EXPOSE 暴露端口 EXPOSE 3000
VOLUME 数据卷 VOLUME [“/data”]
COPY 复制文件进镜像 COPY
ADD 复制文件到镜像、ADD 支持网络 URL 地址作为 src 源 ADD
构建镜像
1
docker build ./webapp

docker build 可以接受一个参数,这个参数是 Dockerfile 文件所在文件夹的路径而非 Dockerfile 的路径。

Dockerfile 使用技巧
  • 使用变量指令 ARG

    ARG 定义变量,在 Dockerfile 文件中可以通过 $+定义的变量名来使用,可以在 Docker build 时设置变量。

    1
    2
    3
    4
    5
    6
    // 定义变量
    ARG TOMCAT_MAJOR
    // Dockerfle 中试用
    $TOMCAT_MAJOR
    // 运行时设置变量
    docker build --build-arg 参数
  • 使用环境变量 ENV

    环境变量也是用来定义参数的东西,与 ARG 指令相类似,环境变量的定义是通过 ENV 这个指令来完成的。

    1
    2
    3
    ENV TOMCAT_MAJOR 8
    // Dcokerfile 中使用
    $TOMCAT_MAJOR
  • 合并命令

    合并 RUN 指令中的命令,我们通常建议采用下面的方式来编写

    1
    2
    3
    RUN npm config set registry https://registry.npm.taobao.org && \
    npm install && \
    npm cache clean --force

    为什么这么做,这就涉及到前面介绍的 Docker 镜像都是由基础镜像一层一层叠加起来的,合并命令后可以减少镜像层的数量,提高镜像构建的速度。

使用 Docker Compose 来管理容器

拿任何一个相对完整的应用系统来说,都不可能是由一个程序独立支撑的,而对于使用 Docker 来部署的分布式计算服务更是这样。而 Docker 推荐的做法是一个程序一个容器,所以这就涉及到各容器的管理。针对这种情况 Docker Compose 就出现了。

安装

我们安装 Docker for Mac 的时候,已经安装好了 Docker Compose。

编写 Docker Compose 配置

Docker Compose 的配置文件是一个基于 YAML 格式的文件。这种语法很简单,随便看几个例子就能学会。我们先看一个例子,这个例子包括了 nginx 容器、server 端容器和数据库容器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
---
version: "3"

networks:
backend:
front:

services:

mysql:
container_name: blog_data
image: mysql:5.7
volumes:
- ../mysql/mysql.cnf:/etc/mysql/my.cnf:ro
- blog-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: root
ports:
- "3306:3306"
networks:
- backend

server:
image: blog_server_image
build:
context: ../
dockerfile: node/Dockerfile
ports:
- "3000:3000"
env_file: ../node/.env
container_name: blog_server
volumes:
- ../server:/usr/blog/server
depends_on:
- mysql
networks:
- backend
- front

nginx:
container_name: blog_web
image: nginx:latest
volumes:
- ../nginx/nginx.conf:/etc/nginx/nginx.conf
- ../web/dist:/etc/nginx/blog
ports:
- "8002:8002"
networks:
- front
depends_on:
- mysql
volumes:
blog-data:
  • 指定镜像

    在这个文件中最重要的无疑是 services 部分了,services 里面每个部分就定义了一个容器。对于容器来说最重要的是指定镜像,可以指定 Docker Hub 中的镜像如上面的 mysql 和 nginx 部分,也可以指定本地 Dockerfile ,如上面的 server 部分。如果是使用 Dockerfile 来构建,docker 将会先执行 docker build 命令生成镜像。

  • 构建依赖

    我们知道有些服务之间有非常强的依赖关系,比如上面的 server 后端服务必须要依赖 mysql 先启动,docker compose 很好的解决了这个问题,可以使用 depend_on 来指定。

  • 文件挂载

    在上面的文件中我使用了 bind mount 挂载方式和 volume 数据卷,这两种方式稍微有点区别,数据卷要先定义,就是文件最先面 volumes 部分。剩下的就是一样了,在配置容器的时候通过 volumes 指定。

  • 配置网络

    在文件最上面的 networks 中定义,定以后就可以在容器中使用。

  • 启动、关闭

    1
    2
    3
    4
    // 启动
    docker compose up -d(后台运行)
    // 关闭
    docker compose dowm

遇到的一些问题

关于 dockerfile 上下文的问题

在使用 docker compose 的时候,报文件不存在。dockerfile 会有一个上下文的存在,默认是 dockerfile 所在的文件夹,可以在 docker compose 中通过 context 来指定。