如何制作和使用DinD的Docker镜像

当使用GitLab的流水线功能时,在经过代码检查、项目打包等步骤之后,可能还需要将项目部署至服务器。如果使用容器的方式来部署项目,那么就需要用到Docker构建镜像和启动容器。本文将介绍如何以GitLab Runner的镜像为基础,构建Docker in Docker(简称DinD)的镜像,然后再介绍如何手动构建镜像和启动容器。

注意
本文的DinD,并不是在一个Docker容器中再运行一个Docker服务的意思,因为这种嵌套容器的方式在某些情况下会有无法预知的行为,所以不建议使用这种方式。本文会在Docker容器中安装整套的Docker CLI工具,然后通过挂载宿主机的/var/run/docker.sock套接字文件来使用Docker功能,详情可以参考:
https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/

一、环境描述

1. 虚拟机配置

  • CPU:单核
  • 内存:2 GB
  • 硬盘:120 GB
  • IP:192.168.190.128

2. 操作系统

  • 版本:CentOS 7.4 x86_64 (1708)
  • 安装方式:Minimal

3. Docker

4. GitLab服务器

5. GitLab Runner

二、构建镜像

1. 创建Dockerfile文件

在shell中运行以下命令:

cd /root/Downloads
vi Dockerfile

Dockerfile的内容,如下所示:

# 使用自建的GitLab Runner镜像
FROM registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/gitlab-runner:10.5.0

# 镜像维护者
MAINTAINER ghoulich@aliyun.com

## 安装Docker
RUN yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
RUN yum install -y docker-ce

## 安装Docker Compose
RUN yum install -y python-pip
RUN pip install --upgrade pip
RUN pip install docker-compose

## 清理系统
RUN yum clean all

每个构建步骤的用途,都在注释中有所说明,本文不再赘述。

2. 构建镜像

在shell中运行以下命令:

docker build -t gitlab-dind-runner:17.12.1 .

构建完成之后,查看新建Docker镜像的信息,如下图所示:

检查DinD镜像状态

3. 上传镜像

本文将Docker镜像交给阿里云托管,在shell中运行以下命令,上传镜像:

# 登录阿里云镜像库
docker login --username=ghoulich@aliyun.com registry.cn-hangzhou.aliyuncs.com
# 为本地镜像创建标签
docker tag gitlab-dind-runner:17.12.1 registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/gitlab-dind-runner:17.12.1
# 推送镜像
docker push registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/gitlab-dind-runner:17.12.1

请根据实际情况,修改上述命令中的用户名和仓库名。

三、启动和使用build-runner容器

使用build-runner容器构建项目的Docker镜像,将构建和部署两个过程分开,减少耦合性。

1. 启动build-runner容器

在shell中运行以下命令,启动一个专用于构建镜像的容器:

mkdir -p /usr/local/gitlab-runner/data
mkdir -p /usr/local/gitlab-runner/config/build
docker run --detach \
    --name build-runner \
    --hostname build-runner \
    --restart always \
    --volume /usr/local/gitlab-runner/config/build:/etc/gitlab-runner \
    --volume /usr/local/gitlab-runner/data:/home/gitlab-runner \
    --volume /var/run/docker.sock:/var/run/docker.sock \
    registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/gitlab-dind-runner:17.12.1

上述命令将容器的名称设置为build-runner,将容器的配置文件目录/etc/gitlab-runner挂载至宿主机的/usr/local/gitlab-runner/config/build目录,将容器的数据目录/home/gitlab-runner挂载至宿主机的/usr/local/gitlab-runner/date目录。

2. 注册Runner实例

GitLab Runner容器启动之后,必须去GitLab服务器进行注册,然后才能在流水线中使用。注册过程,如下图所示:

注册build-runner容器

注册Runner需要填写以下信息:

  • GitLab服务器的URL,本文设置为http://10.15.1.248/
  • GitLab的注册令牌,通常能在GitLab的项目管理页面或系统配置页面找到,本文设置为pDXW_tssA5NHa5K4zSY-
  • 待注册Runner的描述,本文设置为build-runner
  • 待注册Runner的标签,可以设置多个标签(以逗号分割),本文设置为build
  • 是否运行未打标签的构建任务,本文设置为false
  • 是否将待注册的Runner锁定至当前项目,本文设置为false
  • 执行器的类型,本文设置为shell

3. 构建项目镜像

接下来,本文尝试利用build-runner容器手动构建demo项目的镜像,检查该容器是否能够正常工作。假设先前已经为demo项目打过包,生成的jar包存放在宿主机的/usr/local/gitlab-runner/data目录,也就是容器的/home/gitlab-runner目录。

在shell中运行以下命令,创建demo项目的Dockerfile:

docker exec -it build-runner vi /home/gitlab-runner/demo/target/Dockerfile

上述Dockerfile的内容,如下所示:

# 使用官方的java镜像(也可以用自建的代替)
FROM java

# 镜像维护者
MAINTAINER ghoulich@aliyun.com

# 复制jar包
COPY demo-0.0.1-SNAPSHOT.jar /app.jar

# 设置自动启动
CMD java -jar app.jar

保存Dockerfile之后,构建镜像:

docker exec -it build-runner docker build -t demo-image:latest -f /home/gitlab-runner/demo/target/Dockerfile /home/gitlab-runner/demo/target/

上述命令将demo项目的镜像名称设置为demo-image,稍后部署demo容器时会用到这个镜像。

四、启动和使用deploy-runner容器

使用deploy-runner容器部署项目的Docker镜像,将构建和部署两个过程分开,减少耦合性。

1. 启动deploy-runner容器

在shell中运行以下命令,启动一个专用于部署的容器:

mkdir -p /usr/local/gitlab-runner/data
mkdir -p /usr/local/gitlab-runner/config/deploy
docker run --detach \
    --name deploy-runner \
    --hostname deploy-runner \
    --restart always \
    --volume /usr/local/gitlab-runner/config/deploy:/etc/gitlab-runner \
    --volume /usr/local/gitlab-runner/data:/home/gitlab-runner \
    --volume /var/run/docker.sock:/var/run/docker.sock \
    registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/gitlab-dind-runner:17.12.1

2. 注册Runner实例

GitLab Runner容器启动之后,必须去GitLab服务器进行注册,然后才能在流水线中使用。注册过程,如下图所示:

注册deploy-runner容器

注册Runner需要填写以下信息:

  • GitLab服务器的URL,本文设置为http://10.15.1.248/
  • GitLab的注册令牌,通常能在GitLab的项目管理页面或系统配置页面找到,本文设置为pDXW_tssA5NHa5K4zSY-
  • 待注册Runner的描述,本文设置为deploy-runner
  • 待注册Runner的标签,可以设置多个标签(以逗号分割),本文设置为deploy
  • 是否运行未打标签的构建任务,本文设置为false
  • 是否将待注册的Runner锁定至当前项目,本文设置为false
  • 执行器的类型,本文设置为shell

3. 部署项目镜像

接下来,本文尝试利用deploy-runner容器手动部署demo项目的容器,检查该容器是否能够正常工作。由于deploy-runner和build-runner都共享使用宿主机的/var/run/docker.sock套接字文件,因此它们能够和宿主机共享构建缓存(build cache),这就意味着deploy-runner可以直接使用build-runner构建的镜像。

在shell中运行以下命令,部署demo项目的容器:

docker exec -it deploy-runner docker run --detach --name demo --hostname demo --publish 80:8080 demo-image:latest

上述命令将demo项目的容器命名为demo,将容器的8080端口映射至宿主机的80端口。

五、验证测试

1. 检查Runner状态

在浏览器中打开GitLab的Runner配置页面,若如下图所示,则表示build-runner和deploy-runner注册成功:

build-runner和deploy-runner的注册状态

2. 检查容器运行状态

在shell中运行以下命令:

docker ps

若上述命令的返回信息如下图所示,则表示容器运行正常:

检查容器的运行状态

其中,build-runner是专用于构建镜像的容器,deploy-runner是专用于部署容器的容器,demo是demo项目的容器。

3. 测试demo容器

在浏览器中访问以下URL:

http://192.168.190.128/hello

若打开页面如下图所示,则表示demo项目的容器运行成功:

检查demo容器的运行状态

至此,Docker in Docker的镜像已经制作完成了,本文还启动了两个DinD容器,通过一个demo项目,简单演示了构建项目镜像和部署项目容器的过程!