使用 GitLab-CI 来自动创建 Docker 镜像

瞳人


发布于 Nov. 11, 2015, 10:07 p.m.

16 个评论

Docker Gitlab GitLab-CI


简单介绍一下如何使用 GitLab-CI 来自动创建 Docker 镜像, 并上传到仓库.

想法

用 GitLab 来管理 Dockerfile 是一件很显然的事情了. 在每次更改 Dockerfile 之后, 都要手动 build 然后 push 到 registry, 有点烦. 正好这两天自己开了个 registry. 那就采用一种自动的方法来帮助我们做这种机械重复的工作.

首先我想到的是使用 webhook 的响应 结合docker api 来调用 docker build 和 push. 我试验了一下觉得比较麻烦.

后来想到可以使用了 GitLab CI, 并且自 GitLab 8.x 开始已经集成了 GitLab CI Server. 所以也不用额外部署 CI Server 了. 我们要做的工作就是部署一下 GitLab CI runner. 然后在 Dockerfile 的项目里配置一下 .gitlab-ci.yml告诉 GitLab CI runner 如何做就行了.

安装 Docker

在你想用来 build image 的机器上, 显然需要先装好 Docker. 参见 Docker官方文档.

安装 GitLab CI Runner

在用来 build 的机器上我们需要安装 GitLab CI Runner. 官方项目里面提供了很多安装说明. 可以直接找你对应的需要. 这里我就说一下我怎么直接在 Ubuntu 14.04 LTS 上安装的.(对应的官方文档)

1
2
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.deb.sh | sudo bash
sudo apt-get install gitlab-ci-multi-runner

然后注册 runner:

1
sudo gitlab-ci-multi-runner register

当中会让你填写一些信息. 例如你的 gitlab-ci coordinator 的地址和注册这个 runner 的 token, 这两个在你 GitLab 中可以找到. 具体的内容我忘记截图了. 关于 executor 的话, 我这里使用的是 shell, 因为我将 runner 直接运行在物理机的系统上, 想其能够直接使用 docker.

注册好后, 我们可以看 runner 的配置文件, 类似如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# /etc/gitlab-runner/config.toml
concurrent = 1

[[runners]]
  url = "http://gitlab.com/ci"
  token = "******************"
  name = "image builder"
  executor = "shell"
  [runners.ssh]
  [runners.docker]
    image = ""
    privileged = false
  [runners.parallels]
    base_name = ""

关于这些参数可以在官方文档中找到. 注册好的 runner 在 GitLab 中如下图所示.

gitlab ci runner overview

实际显示情况可能和上图有不同, 因为我已经将这个 runner 设置为 specific runner 了. 关于 runner 的说明可以参考 官方文档 configuring runner.

使用 GitLab runner 来 build docker image 的相关说明, 可以参考 官方文档 using docker build. 主要需要注意的是, 为了要让 runner 可以调用 docker 命令, 需要把 gitlab-runner 这个用户加入 docker 所在组.

1
sudo usermod -aG docker gitlab-runner

配置项目

可以参考官方文档 Configuring project. 我这里直接贴出我用的配置了.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
stages:
  - build_image
  - push_image

before_script:
  - docker info

build_image:
  stage: build_image
  script:
    - docker build -t myregistry/aplusplus/ubuntu:14.04 .

push_image:
  stage: push_image
  script:
    - docker push myregistry/aplusplus/ubuntu:14.04

简单地说, stages 定义了你要做几步(stage) 以及他们之间的顺序. 默认每个 stage 都是在之前所有 stage 成功执行后才会执行. 每个 stage 可以包含多个任务(job), 例如上面的 build_image 和 push_image. 这里只定义了一个. 当每个 stage 有多个 jobs 时, 每个 jobs 会并行执行.

效果

当你每次修改项目并 push 到 gitlab 后, runner 就会开始执行你配置的任务了. 如下图:

gitlab ci runner build status

gitlab ci runner build details


哎呦, 不错哦!

16 Comments

瞳人 Jan. 9, 2016, 1:23 p.m. | Reply

这个文章里面的图片有些不一致,因为是完成测试后重新截的图。

ss March 28, 2016, 9:03 a.m. | Reply

image = "" 这个参数什么作用

瞳人 March 28, 2016, 10:58 a.m. | Reply

指定用这个docker image来build

willem April 8, 2016, 2:08 p.m. | Reply

gitlab-ci-multi-runner 1.1.0 (a23a25a)
Using Docker executor with image nginx:latest ...
Pulling docker image nginx:latest ...

Running on runner-3f2f250d-project-1-concurrent-0 via 3e98450ea030...
Cloning repository...
Cloning into '/builds/auto-deploy/gitlab-runner'...
fatal: unable to access 'http://gitlab-ci-token:xxxxxx@iZ23vcrdh4xZ/auto-deploy/gitlab-runner.git/': Couldn't resolve host 'iZ23vcrdh4xZ'

ERROR: Build failed: exit code 1

我是在阿里云上装的ubuntu,然后在ubuntu上搭建的Gitlab以及Runner,想用.gitlab-ci.yml实现自动化测试和部署,结果在拉取Gitlab上的项目时出现无法解析host 'iZ23vcrdh4xZ'的问题,而'iZ23vcrdh4xZ'最开始是阿里云创建好服务器系统时生成的ID,而ubuntu的主机名也是这个,我并未作更改就安装了Gitlab,创建项目时'iZ23vcrdh4xZ'被拼进了获取项目的字符串,后来出现上面的问题后,我把主机名改了,但是创建项目时依然是'iZ23vcrdh4xZ'被拼入字符串。不知道该如何解决。求解。。。

willem April 8, 2016, 2:14 p.m. | Reply

问题解决了,采用shell时,可以在/etc/hosts文件中添加阿里云服务器的内网IP和不能解析的host - iZ23vcrdh4xZ的映射。但是采用docker的话该如何做映射?容器还未运行,不能到容器中做映射。。。这个问题不知如何解决。

瞳人 July 1, 2016, 4:59 p.m. | Reply

不好意思,之前评论邮件提醒出现问题了。所以没有及时看到你的回复。
其实 docker run 支持 --add-host 参数,可以添加自定义的映射,例如如下命令:
docker run -it --add-host svca:10.0.0.9 --add-host svcb:10.0.0.8 ubuntu cat /etc/hosts

bill Oct. 30, 2017, 1:48 p.m. | Reply

gitlab在哪里调用gitlabrunner的啊,我看到我的那个好像是自动使用了gitlabrunner的镜像,找不到在哪个环节更改host解析。求解,谢谢。

simon_c July 10, 2016, 2:18 p.m. | Reply

请教一个问题:
我现在有个场景,多人使用是gitlab-ci测试工程,测试过程中需要用到mysql、redis,我想法是在runner上根据.gitlab-ci.yml的配置启动mysql容器、redis容器,代码测试通过后再进行打包处理。
问题是多个项目同时测试,怎么保障自己的测试代码连接的是自己的mysql服务容器,其实也就是怎么让代码获取要连接的容器ip。
开始想使用mysql容器映射主机的端口,但是多人使用端口可能冲突,不指定外部端口,都不知道怎么让代码获取随机端口。

瞳人 July 10, 2016, 9:43 p.m. | Reply

如果你只是在host上进行测试 mysql、redis 之类的多个项目的话,是不需要绑定到主机上的端口并且暴露的。
其实我是建议你使用 docker run 里面的 --link 参数,例如你有两个项目a和b,假设你的应用 image 叫做 app-image,那么你其实可以分别开 a_app, a_mysql, a_redis, b_app, b_mysql, b_redis。命令大致为:
docker run --name a_mysql mysql-image
docker run --name a_redis redis-image
docker run --name a_app --link a_mysql:mysql --link a_redis:redis app-image
项目b类似。
这样在你的 a_app 容器中就可以通过 a_mysql 来作为项目 a 使用的 mysql 的地址了,同理类似。
不过你要注意这个 --name 指定的名字是不能重复的,一般加个用户名_项目名在前面就不太会重复了。

瞳人 July 10, 2016, 9:47 p.m. | Reply

不小心说错了,使用 --link a_mysql:mysql 的话,在 a_app 中间应该是使用 mysql 来作为访问名字,因为 --link 是采用的 container_name:alias 的格式。

simon_c July 11, 2016, 11:26 a.m. | Reply

首先感谢你的回复,gitlab测试这个不太懂,我们这的研发之前就是 mvn test,我现在是runner是实体机,代码测试在实体机上,需要连接自己的mysql容器。
你的意思是,mvn test也跑在容器里是吧,然后,这个容器再link mysql容器,请在mvn test怎么也生成在一个容器里运行?
另外,请问我在.gitlab-ci.yml配置docker run -d centos6-ssh启动容器,在gitlab管理界面查看日志可以看到这条命令返回了一个值,就是容器id,我想问一下,.gitlab-ci.yml这个配置文件里可以设置获取这个返回值吗,我.gitlab-ci.yml文件下边的配置需要用到这个值。

瞳人 July 11, 2016, 12:19 p.m. | Reply

第一个问题:
mvn test 运行在容器里,有两种方法:
第一种就是,使用 docker container 来作为 runner,有现成的 runner 的容器,你扩展一下就行了。
第二种就是,自己开一个 mvn 测试环境的容器,然后运行在你的 runner 实体机上,然后用 runner 来操作这个容器。
第二个问题:
haha=$(docker run -d centos6-ssh)
这个 haha 变量就存了这个值。

simon_c July 11, 2016, 1:43 p.m. | Reply

关于变量的问题,一个stages里边的变量,在其他的stages里边无法获取,有没有公共变量的概念。
我想在stages:rm_docker_container里边使用stages: build_mysql生成的变量,但是无法获取。

stages:
- build_redis
- build_mysql
- rm_docker_container
- test_build

before_script:
- docker info

build_image:
stage: build_redis
script:
- docker run -d -P --name=mytest1 redis

push_image:
stage: build_mysql
script:
- export container_id=$(docker run -d -e MYSQL_ROOT_PASSWORD=MYSQL mysql)
- echo $container_id
- export MYSQLIP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' $container_id)
- echo $MYSQLIP
- ping $MYSQLIP -c 5

rm_container:
stage: rm_docker_container
script:
- echo $MYSQLIP
- echo $container_id
- docker stop mytest1
- docker stop $container_id
- docker rm mytest1
- docker rm $container_id

test:
stage: test_build
script:
- docker run -d centos6-ssh

瞳人 July 11, 2016, 2:52 p.m. | Reply

哦哦,明白了。那你可以试试 把这个id重定向到文件中,然后在后面rm的stage里从这个文件里读取一下。

Simon_c July 11, 2016, 7:50 p.m. | Reply

谢谢,我把IP写到hosts里边了。

Jarvan July 6, 2017, 10:12 a.m. | Reply

docker 搭建gitlab-ci中runner的注册地址怎么填?


Leave a Comment:

博客搜索

友情链接

公告

本博客代码已经公布在 Github 上,欢迎交流指正。

QQ 邮箱对 mailgun 不太友好, 所以使用 QQ 邮箱的评论, 可能会无法及时收到邮件。我会尽快寻找其他解决方案的。

本人现在独自使用 linode vps, 20 美元/月, 感觉压力大, 如果有意一起合租, 可以联系我. 在我的任意一篇文章下面留言即可. 关于使用方式, 现在倾向于使用 docker.