Tag Archives: docker

使用 Docker 构建

使用 Docker 构建

原文:https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/ci/docker/using_docker_build.md

GitLab CI 允许你使用 Docker Engine 构建和测试基于 Docker 的项目。

这也允许您使用docker-compose和其他 docker-enabled 的工具。

持续集成/持续部署的新趋势之一是:

  1. 创建应用程序镜像,
  2. 针对创建的镜像运行测试,
  3. 将镜像推送到远程 Registry,并
  4. 从推送的镜像部署到服务器。

当您的应用程序已经具有可用于创建和测试镜像的Dockerfile时,它也很有用:

$ docker build -t my-image dockerfiles/
$ docker run my-docker-image /script/to/run/tests
$ docker tag my-image my-registry:5000/my-image
$ docker push my-registry:5000/my-image

这需要 GitLab Runner 的特殊配置,以在作业期间启用docker支持。

Runner 配置

在作业中有三种方法可以使用docker builddocker run,每个都有自己的考虑。

使用 Shell 执行器

最简单的方法是在shell执行模式下安装 GitLab Runner。然后 GitLab Runner 作为gitlab-runner用户执行作业脚本。

  1. 安装 GitLab Runner

  2. 在 GitLab Runner 安装期间,选择shell作为执行作业脚本或使用命令的方法:

    sudo gitlab-ci-multi-runner register -n \
      --url https://gitlab.com/ \
      --registration-token REGISTRATION_TOKEN \
      --executor shell \
      --description "My Runner"
    
  3. 在服务器上安装 Docker Engine。

    有关如何在不同系统上安装 Docker Engine 的更多信息,请参阅 Supported installations

  4. 新增 gitlab-runner 用户到 docker 组:

    sudo usermod -aG docker gitlab-runner
    
  5. 验证gitlab-runner是否可以访问Docker:
    sudo -u gitlab-runner -H docker info
    

    现在你可以通过将docker info添加到.gitlab-ci.yml中来验证一切是否正常:

    before_script:
      - docker info
    
    build_image:
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    
  6. 现在可以使用docker命令,如果需要可以安装docker-compose

注:
* 通过在docker组中添加gitlab-runner,你可以有效地授予gitlab-runner的完整的 root 权限。有关更多信息,请阅读 On Docker security: docker group considered harmful

使用 docker-in-docker 执行器

第二种方法是使用专门的 Docker 镜像 docker-in-docker(dind),它安装了所有工具(dockerdocker-compose),并以特权模式在该镜像的上下文中运行作业脚本。

为了做到这一点,请按以下步骤操作:

  1. 安装 GitLab Runner

  2. 从命令行注册 GitLab Runner 以使用dockerprivileged模式:

    sudo gitlab-ci-multi-runner register -n \
      --url https://gitlab.com/ \
      --registration-token REGISTRATION_TOKEN \
      --executor docker \
      --description "My Docker Runner" \
      --docker-image "docker:latest" \
      --docker-privileged
    

    上面的命令将注册一个新的 Runner 来使用 Docker 所提供的特殊docker:latest镜像。请注意,它使用privileged模式启动构建和服务容器。如果要使用docker-in-docker模式,您始终必须在 Docker 容器中使用privileged = true

    上面的命令将创建一个类似于这个的config.toml条目:

    [[runners]]
      url = "https://gitlab.com/"
      token = TOKEN
      executor = "docker"
      [runners.docker]
        tls_verify = false
        image = "docker:latest"
        privileged = true
        disable_cache = false
        volumes = ["/cache"]
      [runners.cache]
        Insecure = false
    
  3. 您现在可以在构建脚本中使用docker(请注意包含docker:dind服务)
    image: docker:latest
    
    # When using dind, it's wise to use the overlayfs driver for
    # improved performance.
    variables:
      DOCKER_DRIVER: overlay
    
    services:
      - docker:dind
    
    before_script:
      - docker info
    
    build:
      stage: build
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    

Docker-in-Docker 运行良好,是推荐的配置,但并不是没有挑战:

  • 启用--docker-privileged禁用了容器的所有安全机制,并使你的主机由于特权升级而暴露,从而导致容器突破(主机-容器屏障)。有关更多信息,请查看官方 Docker 文档 Runtime privilege and Linux capabilities
  • 当使用 docker-in-docker 时,每个作业都处于一个干净的环境中,没有过去的历史。并发作业工作正常,因为每个构建都获得自己的 Docker Engine 实例,因此不会相互冲突。但这也意味着作业可能会更慢,因为没有缓存层。
  • 默认情况下,docker:dind使用--storage-driver vfs,这是最慢的形式。要使用其他驱动程序,请参阅使用 overlayfs 驱动程序

使用这种方法的示例项目可以在这里找到:https://gitlab.com/gitlab-examples/docker.

Use Docker socket binding

第三种方法是将/var/run/docker.sock绑定装载到容器中,以便 docker 在该镜像的上下文中可用。

为了做到这点,遵循以下步骤:

  1. 安装 GitLab Runner.

  2. 从命令行注册 GitLab Runner 以使用docker并共享/var/run/docker.sock

    sudo gitlab-ci-multi-runner register -n \
      --url https://gitlab.com/ \
      --registration-token REGISTRATION_TOKEN \
      --executor docker \
      --description "My Docker Runner" \
      --docker-image "docker:latest" \
      --docker-volumes /var/run/docker.sock:/var/run/docker.sock
    

    上面的命令将注册一个新的 Runner 来使用 Docker 提供的特殊docker:latest镜像。请注意,它正在使用 Runner 本身的 Docker 守护进程,docker 命令产生的任何容器都将是 Runner 的兄弟,而不是所运行程序的子进程。这可能会有不适合您的工作流程的复杂性和局限性。

    上面的命令将创建一个类似于这个的config.toml条目:

    [[runners]]
      url = "https://gitlab.com/"
      token = REGISTRATION_TOKEN
      executor = "docker"
      [runners.docker]
        tls_verify = false
        image = "docker:latest"
        privileged = false
        disable_cache = false
        volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
      [runners.cache]
        Insecure = false
    
  3. 您现在可以在构建脚本中使用docker(请注意,在 Docker 执行器中使用 Docker 时,不需要包含docker:dind服务):
    image: docker:latest
    
    before_script:
    - docker info
    
    build:
      stage: build
      script:
      - docker build -t my-docker-image .
      - docker run my-docker-image /script/to/run/tests
    

虽然上述方法避免在特权模式下使用 Docker,但您应该了解以下影响:

  • 共享 docker 守护进程,禁用了容器的所有安全机制,并将主机暴露给特权提升,从而导致容器突破屏障。例如,如果一个项目运行docker rm -f $(docker ps -a -q),它将删除 GitLab Runner 容器。
  • 并发作业可能无效;如果你的测试创建了具有特定名称的容器,它们可能会相互冲突。
  • 将文件和目录从源代码库共享到容器中可能无法正常工作,因为卷装载是在主机上下文中完成的,而不是在构建容器中,例如:
    docker run --rm -t -i -v $(pwd)/src:/home/app/src test-image:latest run_app_tests
    

使用 OverlayFS 驱动程序

默认情况下,使用docker:dind时,Docker 使用vfs存储驱动程序,每次运行时都会拷贝文件系统。磁盘操作非常密集,如果使用不同的驱动程序(例如overlay),则可以避免这种情况。

  1. 确保使用最近的内核,最好是>= 4.2
  2. 检查overlay模块是否加载:
    sudo lsmod | grep overlay
    

    如果没有结果,那就没有加载。加载之:

    sudo modprobe overlay
    

    如果一切顺利,您需要确保在系统重启时也加载该模块。Ubuntu 系统上是通过编辑/etc/modules完成的。添加以下行:

    overlay
    
  3. .gitlab-ci.yml顶部定义一个变量以使用该驱动:
    variables:
      DOCKER_DRIVER: overlay
    

使用 GitLab 容器 Registry

注:
- 此功能需要 GitLab 8.8 和 GitLab Runner 1.2。
- 从 GitLab 8.12 开始,如果你的帐户启用了两步认证,则需要传递个人访问令牌而不是密码,才能登录到 GitLab 的 Container Registry。

一旦构建了 Docker 镜像,就可以将其推送到内置的 GitLab 容器 Registry 中。例如,如果你在 runner 上使用 docker-in-docker,那.gitlab-ci.yml可能如下:

 build:
   image: docker:latest
   services:
   - docker:dind
   stage: build
   script:
     - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.example.com
     - docker build -t registry.example.com/group/project/image:latest .
     - docker push registry.example.com/group/project/image:latest

必须使用为你创建的特殊gitlab-ci-token用户,才能推送到连接到项目的 Registry。它的密码由$CI_JOB_TOKEN变量提供。这允许您自动构建和部署 Docker 镜像。

您也可以利用其他变量来避免硬编码:

services:
  - docker:dind

variables:
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME

before_script:
  - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY

build:
  stage: build
  script:
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG

在这里,$CI_REGISTRY_IMAGE将解析为与该项目相关联的 Registry 地址,$CI_COMMIT_REF_NAME将解析为该作业所在分支或标签的名称。还声明了我们自己的变量$IMAGE_TAG,将两者结合起来,以节省我们在script部分中的输入。

这是一个更详细的例子,将任务分解为 4 个流水线(pipeline)阶段,包括并行运行的两个测试。build存储在容器 Registry 中,并在后续阶段使用,需要时则下载该镜像。对master的更改也被标记为latest,并使用特定于应用程序的部署脚本进行部署:

image: docker:latest
services:
  - docker:dind

stages:
  - build
  - test
  - release
  - deploy

variables:
  CONTAINER_TEST_IMAGE: registry.example.com/my-group/my-project/my-

image:$CI_COMMIT_REF_NAME
  CONTAINER_RELEASE_IMAGE: registry.example.com/my-group/my-project/my-image:latest

before_script:
  - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.example.com

build:
  stage: build
  script:
    - docker build --pull -t $CONTAINER_TEST_IMAGE .
    - docker push $CONTAINER_TEST_IMAGE

test1:
  stage: test
  script:
    - docker pull $CONTAINER_TEST_IMAGE
    - docker run $CONTAINER_TEST_IMAGE /script/to/run/tests

test2:
  stage: test
  script:
    - docker pull $CONTAINER_TEST_IMAGE
    - docker run $CONTAINER_TEST_IMAGE /script/to/run/another/test

release-image:
  stage: release
  script:
    - docker pull $CONTAINER_TEST_IMAGE
    - docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE
    - docker push $CONTAINER_RELEASE_IMAGE
  only:
    - master

deploy:
  stage: deploy
  script:
    - ./deploy.sh
  only:
    - master

使用容器 Registry 的注意事项:

  • 在运行命令之前必须先登录到容器 Registry。把它放在before_script里,会在每个作业之前运行它。
  • 使用docker build --pull可以确保 Docker 在构建前获取 base 镜像的任何更改,以防您的缓存失效。这需要运行更长时间,但意味着不会遇到未打安全补丁的 base 镜像。
  • 在每个docker run之前做一个明确的docker pull,确保获取刚构建的最新镜像。如果您正在使用多个会在本地缓存镜像的 Runner,这一点尤为重要。在镜像标签中使用 git SHA 又使得这不太必要,因为每个作业都将是唯一的,并且您不应该有一个过时的镜像,但是如在依赖更改后,重新构建给定的 Commit,这仍然可能(有过时的镜像)。
  • 同时发生多个作业的情况下,你不会想直接构建为latest

GitLab Runners

GitLab Runners

Original URL: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/ci/runners/README.md

GitLab CI 中,Runners 运行你的 yaml。Runner 是一个独立/隔离的(虚拟)机器,它通过 GitLab CI 的协调器(coordinator) API 拾取作业。

Runner 可以服务特定的项目,或为 GitLab CI 的任何项目提供服务。为所有项目提供服务的 Runner 称为 Shared Runner

理想情况下,GitLab Runner 不应与 GitLab 安装在相同机器上。阅读需求文档以获取更多信息。

Shared vs. Specific Runners

具体的 Runner 仅针对指定的项目运行。共享的 Runner 可以为启用了 Allow shared Runners 的项目运行作业。

Shared Runners 对多个项目间需求类似的作业很有用。您可以使用一个或多个 Runner 来处理多个项目,而不是让多个 Runner 闲置等待多个项目。这样可以更容易维护和更新 Runner。

Specific Runners 对于要求特殊的作业,或有特定需求的项目很有用。如果一个作业有一定的要求,你可以设置一个 Specific Runner 来搞,而不必为所有 Runner 这样做。例如,如果要部署某个项目,可以设置 Specific Runner 以获取正确的凭据。

CI 活动频繁旺盛的项目也可以从使用 Specific Runner 中受益。通过 Specific Runners 可确保 Runner 不被其他项目的作业阻塞。

您可以设置 Specific Runner 供多个项目使用。与 Shared Runner 的区别在于,必须为 Runner 显式地启用上述每个项目,才能运行这些项目的作业。

Specific Runner 不会自动与 fork 出去的项目共享。fork 将复制所克隆的代码仓库 CI 设置(jobsallow shared 等)。

创建并注册 Runner

有几种方法可以创建 Runner。只有创建后,注册才能确定其为SharedSpecific状态。

安装 Runner 实例的不同方法,请参阅文档

安装 Runner 后,可将其注册为SharedSpecific。如果您有 GitLab 实例的管理员访问权限,则只能注册一个Shared Runner

注册Shared Runner

如果您是链接的 GitLab 实例上的管理员,则只能注册一个Shared Runner
(You can only register a shared Runner if you are an admin on the linked GitLab instance.)

在 GitLab CI 实例的admin/runners页面上获取shared-Runner令牌。

shared token

现在只需注册 Runner 即可:

sudo gitlab-ci-multi-runner register

从 GitLab 8.2 起,Shared Runners 默认启用,但可以使用DISABLE SHARED RUNNERS按钮禁用。以前版本的 GitLab 中,Shared Runners 默认为禁用。

注册Specific Runner

Registering a specific can be done in two ways:

  1. Creating a Runner with the project registration token
  2. Converting a shared Runner into a specific Runner (one-way, admin only)

There are several ways to create a Runner instance. The steps below only concern registering the Runner on GitLab CI.

Registering a Specific Runner with a Project Registration token

To create a specific Runner without having admin rights to the GitLab instance, visit the project you want to make the Runner work for in GitLab CI.

Click on the Runner tab and use the registration token you find there to setup a specific Runner for this project.

project Runners in GitLab CI

To register the Runner, run the command below and follow instructions:

sudo gitlab-ci-multi-runner register

Lock a specific Runner from being enabled for other projects

You can configure a Runner to assign it exclusively to a project. When a Runner is locked this way, it can no longer be enabled for other projects. This setting is available on each Runner in Project Settings > Runners.

Making an existing Shared Runner Specific

If you are an admin on your GitLab instance, you can make any shared Runner a specific Runner, but you can not make a specific Runner a shared Runner.

To make a shared Runner specific, go to the Runner page (/admin/runners) and find your Runner. Add any projects on the left to make this Runner run exclusively for these projects, therefore making it a specific Runner.

making a shared Runner specific

Using Shared Runners Effectively

If you are planning to use shared Runners, there are several things you should keep in mind.

Use Tags

You must setup a Runner to be able to run all the different types of jobs that it may encounter on the projects it's shared over. This would be problematic for large amounts of projects, if it wasn't for tags.

By tagging a Runner for the types of jobs it can handle, you can make sure shared Runners will only run the jobs they are equipped to run.

For instance, at GitLab we have Runners tagged with "rails" if they contain the appropriate dependencies to run Rails test suites.

Prevent Runner with tags from picking jobs without tags

You can configure a Runner to prevent it from picking jobs with tags when the Runner does not have tags assigned. This setting is available on each Runner in Project Settings > Runners.

Be careful with sensitive information

If you can run a job on a Runner, you can get access to any code it runs and get the token of the Runner. With shared Runners, this means that anyone that runs jobs on the Runner, can access anyone else's code that runs on the Runner.

In addition, because you can get access to the Runner token, it is possible to create a clone of a Runner and submit false jobs, for example.

The above is easily avoided by restricting the usage of shared Runners on large public GitLab instances and controlling access to your GitLab instance.

Forks

Whenever a project is forked, it copies the settings of the jobs that relate to it. This means that if you have shared Runners setup for a project and someone forks that project, the shared Runners will also serve jobs of this project.

Attack vectors in Runners

Mentioned briefly earlier, but the following things of Runners can be exploited. We're always looking for contributions that can mitigate these Security Considerations.

在容器内运行 GitLab Runner

在容器内运行 GitLab Runner

这描述如何在 Docker 容器中运行 GitLab Runner。

Docker 镜像安装及配置

首先安装 Docker:

curl -sSL https://get.docker.com/ | sh

需要在gitlab-runner容器中装载一个用于配置和其他资源的配置存储卷,:

docker run -d --name gitlab-runner --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest

或者,你可以使用配置容器来装载自定义数据卷:

docker run -d --name gitlab-runner-config \
    -v /etc/gitlab-runner \
    busybox:latest \
    /bin/true

docker run -d --name gitlab-runner --restart always \
    --volumes-from gitlab-runner-config \
    gitlab/gitlab-runner:latest

如果打算使用 Docker 作为产生 Runners 的方法,则要这样装载 docker socket:

docker run -d --name gitlab-runner --restart always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  gitlab/gitlab-runner:latest

注册 runner (查看 Runner 文档了解如何获取令牌):

docker exec -it gitlab-runner gitlab-runner register

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )
https://gitlab.com
Please enter the gitlab-ci token for this runner
xxx
Please enter the gitlab-ci description for this runner
my-runner
INFO[0034] fcf5c619 Registering runner... succeeded
Please enter the executor: shell, docker, docker-ssh, ssh?
docker
Please enter the Docker image (eg. ruby:2.1):
ruby:2.1
INFO[0037] Runner registered successfully. Feel free to start it, but if it's
running already the config should be automatically reloaded!

Runner 应该已经启动了,已准备好构建项目!

请确保阅读了有关 GitLab Runner 最常见问题的 FAQ

更新

拉取最新的(latest)版本:

docker pull gitlab/gitlab-runner:latest

停止并删除现有容器:

docker stop gitlab-runner && docker rm gitlab-runner

像原来一样启动容器:

docker run -d --name gitlab-runner --restart always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  gitlab/gitlab-runner:latest

注意:您需要使用与原来装载数据卷相同的方法(-v /srv/gitlab-runner/config:/etc/gitlab-runner--volumes-from gitlab-runner

安装受信的 SSL 服务器证书

如果你的 GitLab CI 服务器在使用自签名 SSL 证书,那应确保 GitLab CI 服务器证书被 gitlab-ci-multi-runner 容器信任,以便它们能够相互通信。

The gitlab/gitlab-runner image is configured to look for the trusted SSL certificates at /etc/gitlab-runner/certs/ca.crt, this can however be changed using the -e "CA_CERTIFICATES_PATH=/DIR/CERT" configuration option.

Copy the ca.crt file into the certs directory on the data volume (or container).
The ca.crt file should contain the root certificates of all the servers you want gitlab-ci-multi-runner to trust. The gitlab-ci-multi-runner container will import the ca.crt file on startup so if your container is already running you may need to restart it for the changes to take effect.

gitlab/gitlab-runner镜像被配置为在/etc/gitlab-runner/certs/ca.crt上查找受信的 SSL 证书,但可以使用-e "CA_CERTIFICATES_PATH=/DIR/CERT"来配置。

ca.crt文件复制到数据卷(或容器)上的certs目录中。
ca.crt文件应包含所有需要 gitlab-ci-multi-runner 信任的服务器根证书。启动时,gitlab-ci-multi-runner 容器将导入ca.crt文件,因此如果你的容器已经运行,则需重启生效。

Alpine Linux

你还可以使用替代的基于 Alpine Linux 的镜像,文件体积更小:

gitlab/gitlab-runner    latest              3e8077e209f5        13 hours ago        304.3 MB
gitlab/gitlab-runner    alpine              7c431ac8f30f        13 hours ago        25.98 MB

Alpine Linux image is designed to use only Docker as the method of spawning runners.

原本的 gitlab/gitlab-runner:latest 基于 Ubuntu 14.04 LTS。

SELinux

某些发行版(CentOS,RedHat,Fedora)默认使用 SELinux 来增强底层系统的安全性。

处理这种配置时必须特别小心。

  1. If you want to use Docker executor to run builds in containers you need to access the /var/run/docker.sock.
    However, if you have a SELinux in enforcing mode, you will see the Permission denied when accessing the /var/run/docker.sock.
    Install the selinux-dockersock and to resolve the issue: https://github.com/dpw/selinux-dockersock.

  2. Make sure that persistent directory is created on host: mkdir -p /srv/gitlab-runner/config.

  3. Run docker with :Z on volumes:

docker run -d --name gitlab-runner --restart always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner:Z \
  gitlab/gitlab-runner:latest

More information about the cause and resolution can be found here:
http://www.projectatomic.io/blog/2015/06/using-volumes-with-docker-can-cause-problems-with-selinux/

[已过时] 部署 Docker Registry 服务

本文所述已经过时,已无参考价值。

本文阐释了怎样部署私有的 Docker Registry 服务 —— 或为公司私用,或公开给其他用户使用。例如,你公司可能需要私人的 Registry 来支持持续集成(CI)。又或,你的公司可能有大量镜像方式的产品或服务,你想以公司品牌的方式来整体提供和呈现。

Continue reading