Docker 服务未在 Ansible 中启动

Docker service is not started in Ansible

我正在学习 Ansible,想在我的笔记本电脑上本地使用它,目前我正在使用 "includes"。

我想准备一个剧本来导入一些其他任务(安装基础包,设置 git、vim 和 docker)并执行它。

All the code is hosted in GitLab and I'm using their free CI service to test the plays.

CI 作业将 运行 直到检查 docker 服务是否 运行ning。此时,播放将失败并显示以下消息:

fatal: [localhost]: FAILED! => {
    "changed": true, 
    "cmd": ["service", "docker", "restart"], 
    "delta": "0:00:00.176233",
    "end": "2017-09-28 18:49:56.194752",
    "failed": true,
    "msg": "non-zero return code",
    "rc": 1,
    "start": "2017-09-28 18:49:56.018519",
    "stderr": "",
    "stderr_lines": [],
    "stdout": "",
    "stdout_lines": []
}

我在我的笔记本电脑上创建了一个 docker 容器 (docker run --rm -ti debian) 并在本地执行了播放,但它在同一个地方失败了。

但是,如果容器是用privileged标志创建的,我可以手动启动服务,然后重新执行播放。这一次,它会成功完成。


所以,我的问题是:

PS: 目前,我并不是在研究最佳实践,我只是想让这个 运行 有所作为一起玩。

环境:

--- --- ---

gitlab-ci.yml 文件:

image: debian:latest

variables:
  HOST_INVENTORY: "./hosts"
  INCLUDES_DIR: "./gists/includes"

before_script:
  - apt-get update -qq
  - apt-get install -y curl gcc g++ openssh-server openssh-client python python-dev python-setuptools libffi-dev libssl-dev
  - easy_install pip
  - pip install ansible

stages:
  - syntax_check
  - install

check:
  stage: syntax_check
  script:      
    - ansible-playbook -i $HOST_INVENTORY $INCLUDES_DIR/play.yml --limit 'local' --syntax-check;

run_includes:
    stage: install
    script:
        - ANSIBLE_PIPELINING=True ansible-playbook -i $HOST_INVENTORY $INCLUDES_DIR/play.yml --limit 'local';

play.yml很简单,只导入了一些剧本:

- hosts: local
  become: yes
  become_method: sudo

  pre_tasks:
    - import_tasks: tasks/pre.yml # update package manager cache

  tasks:
    - import_tasks: tasks/common.yml
    - import_tasks: tasks/docker.yml

docker 任务:

- name: Dependencies
  package:
    name: "{{ item }}"
    state: installed
  with_items:
    - apt-transport-https
    - ca-certificates
    - curl
    - gnupg2
    - software-properties-common

- name: Docker module dependencies
  pip:
      name: docker-py

- name: Add Docker key
  shell: curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | apt-key add -

- name: Add Docker repo
  shell: echo "deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo $ID) $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list

- name: Install Docker
  apt:
    pkg: docker-ce
    state: installed
    update_cache: yes

- name: Ensure Docker group is present
  group:
    name: docker
    state: present

- name: Add current user to the Docker group
  user:
    name: "{{ ansible_user }}"
    groups:
      - docker
    append: yes

- name: Ensure service is enabled
  command: service docker restart

- name: Pull images from Docker hub
  docker_image:
    name: "{{ item }}"
  with_items:
    - debian
    - cern/cc7-base

所以我在 gitlab.com 上创建了一个示例项目,其中 运行s 在 运行ner

上的几个命令
$ echo PWD is $PWD
PWD is /builds/tarunlalwani/testci
$ id
uid=0(root) gid=0(root) groups=0(root)
$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1  20260  2984 ?        Ss   19:41   0:00 /bin/bash
root         7  0.0  0.1  20420  2652 ?        S    19:41   0:00 /bin/bash
root        10  0.0  0.0  17500  1996 ?        R    19:41   0:00 ps aux
$ which systemctl
/bin/systemctl
$ systemctl status docker
Failed to get D-Bus connection: Unknown error -1
ERROR: Job failed: exit code 1

如您所见,我们 运行 在一个容器中,因此您的 ansible 脚本将无法运行。没有要启动或结束的 docker 服务。此外,由于您在 docker 容器内,重新启动 docker 容器也意味着终止您正在 运行 的容器。

您需要设置一个 Ubuntu VM,然后在其上设置带有 Shell 执行程序的 Gitlab Runner。 shell 执行器意味着您在该 VM 上的命令 运行,它将具有 systemctldocker 服务

另一种方法是使用 GitLab's dind service,这样我们就可以使用已经提供的共享 运行ners 在容器内测试 playbook。

这里需要两件事:

  1. A Dockerfile 在哪里构建一个基础镜像,满足 运行 Ansible 的所有要求。
  2. gitlab-ci 文件修改为 运行 容器内的作业。

例如,Dockerfile 可能如下所示:

FROM debian:latest
ARG USERNAME

RUN apt-get update && \
    apt-get install -y curl \
                       git \
                       gcc \
                       g++ \
                       libffi-dev \
                       libssl-dev \
                       openssh-client \
                       openssh-server \
                       python \
                       python-dev \
                       python-setuptools \
                       sudo

RUN easy_install pip && \
    pip install ansible \
                jmespath

RUN useradd -ms /bin/bash $USERNAME
USER $USERNAME
WORKDIR /home/$USERNAME

然后,在 gitlab-ci.yml 文件中,我们可以有如下内容:

image: docker:latest
services:
  - docker:dind

variables:
  DOCKER_IMAGE: "registry.gitlab.com/<YOUR_USER>/<YOUR_REPO>/dummy-image"
  CONTAINER_NAME: "test"
  IMAGE_USERNAME: "dummy"

stages:
  - build
  - check

before_script:
  - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com
after_script:
  - docker rm -f $(docker ps -aq)
  - docker rmi $DOCKER_IMAGE
  - docker logout registry.gitlab.com

build_image:
  stage: build
  script:
    - docker build --pull -t $DOCKER_IMAGE --build-arg USERNAME=$IMAGE_USERNAME .
    - docker push $DOCKER_IMAGE
  when: manual

check_version:
  stage: check
  script:
      - docker run -di --name $CONTAINER_NAME $DOCKER_IMAGE
      - docker exec $CONTAINER_NAME /bin/bash -c "ansible-playbook --version"

这还有一个额外的好处,即 Ansible 到 运行 的所有先决条件都在 build 阶段设置,并且不需要在每次 CI 进程是 运行(就像问题中的原始 gitlab-ci.yml 文件一样)。