プロキシやネットワークアドレス重複を乗り越えてGitLab CIでMolecule

はじめに

前回の記事 で「GitLab CIを使った継続的なMoleculeによるRoleのテスト」ができるようになりました。 しかし、プロキシ等がある環境では素直にMoleculeを実行することができないことが多いです。 例に漏れず、自分の環境も素直にいきませんでした。

今回は、自分が直面した プロキシネットワークアドレス重複 といった課題を解決してGitLab CIでMoleculeを実行する方法を記録します。

環境と問題点

f:id:nnstt1:20200608014959p:plain

プロキシ

今回の環境では、社内LANからインターネットに出る際にプロキシサーバを経由する必要があります。 GitLab CIで使用するビルドコンテナ(今回は docker:19.03.11 を使用)にMoleculeをインストールする際、インターネットに繋ぐためプロキシの設定をする必要があります。

また、GitLab CIのビルドコンテナからサービスコンテナ(dind)にアクセスする際、プロキシサーバを経由することができないため直接アクセスするよう設定が必要です。

ネットワークアドレス重複

今回の環境のネットワークアドレス(サーバセグメント)は 172.17.0.0/16 となっています。 これはDockerがサーバ内で作成して使用するブリッジのネットワークアドレスと同じです。 そのため、デフォルトのままではDockerホストサーバでdockerサービスを起動させるとDocker内部のネットワークへルーティングされてしまい、Dockerホストサーバから社内の別サーバへ繋がりません。

今回はGitLab Runnerコンテナを docker executer としてDockerホストサーバ上で動かしており、このサーバのDockerが使うネットワークアドレスは事前に変更しています。 しかし、GitLab CIの サービスコンテナ として使用する docker:19.03.11-dind コンテナイメージはデフォルトの 172.17.0.0/16 を使うため、社内ネットワークアドレスと重複してしまいます。そのため、サービスコンテナからGitLabサーバへは繋がりません。

今回はMoleculeのテストでGitLabサーバ内プライベートレジストリにあるコンテナイメージをpullしてテストするため、サービスコンテナからGitLabサーバへ繋げる必要があります。

解決策

プロキシとネットワークアドレス重複の問題は以下の方法で解決できました。

【プロキシ】molecule実行用dockerコンテナイメージ作成

Molecule公式 では .gitlab-ci.ymlapk update コマンドを実行していますが、 プロキシ環境下ではここで詰まってしまうため、環境変数 http_proxy にプロキシサーバを指定してあげる必要があります。 また、Moleculeをインストールする際の pip コマンドは別途 --proxy オプションをつけて実行する必要があります。

.gitlab-ci.yml 内でプロキシ設定を追加してもよいのですが、Moleculeインストールにそこそこ時間が掛かってしまうため、Moleculeをインストール済みのdockerコンテナをビルドして .gitlab-ci.yml から呼び出すようにします。

  • Dockerfile(docker:19.03.11)
FROM docker:19.03.11

ENV http_proxy="http://proxyserver:proxyport" \
        https_proxy="http://proxyserver:proxyport"

RUN apk update

RUN apk add --no-cache \
    python3-dev py3-pip gcc git curl build-base \
    autoconf automake py3-cryptography linux-headers \
    musl-dev libffi-dev openssl-dev openssh

RUN python3 -m pip install ansible molecule[lint] docker --proxy http://proxyserver:proxyport 

【プロキシ】dindのプロキシ設定

サービスコンテナ(dind)でdockerdサービスが起動する際に、$HOME/.docker/config.json が読み込まれて設定されます。 GitLab Runnerの設定ファイル config.toml に下記の pre_build_script=〜 を追加することで、ビルドコンテナやサービスコンテナ起動時に $HOME/.docker/config.json を作成することができます。このconfig.jsonにプロキシ設定を記述するように pre_build_script を設定しています。(ワンライナーjsonが書かれていて見難いですが…)

config.toml にプロキシを設定することで、このランナーが起動するビルドコンテナやサービスコンテナには常に $HOME/.docker/config.json が作られることになります。.gitlab-ci.yml でも同じことができるようですが、その場合はプロジェクト毎にプロキシの設定を .gitlab-ci.yml に記述する必要があるようです。

[[runners]]
  name = "gitlab-runner"
  url = "https://gitlab.nnstt1.work/"
  token = "TOKEN"
  executor = "docker"
  pre_build_script = "mkdir -p $HOME/.docker/ && echo \"{ \\\"proxies\\\": { \\\"default\\\": { \\\"httpProxy\\\": \\\"$HTTP_PROXY\\\", \\\"httpsProxy\\\": \\\"$HTTPS_PROXY\\\", \\\"noProxy\\\": \\\"$NO_PROXY\\\" } } }\" > $HOME/.docker/config.json"
  [runners.custom_build_dir]
  [runners.docker]
    image = "docker:19.03.11"
    privileged = true
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/certs/client", "/cache"]
    shm_size = 0
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]

【ネットワーク重複】dindコンテナイメージ作成

docker:19.03.11-dind コンテナイメージ内の /etc/docker/ にネットワークアドレスの設定を記述した daemon.json を配置したコンテナイメージを使用することで、dind で使用するDocker用ネットワークアドレスを変更することができます。 今回はサービスコンテナ(dind)で使用するネットワークアドレスを 10.10.0.1/16 としています。

{
  "bip": "10.10.0.1/16"
}
  • Dockerfile(docker:19.03.11-dind)
FROM docker:19.03.11-dind

COPY daemon.json /etc/docker/daemon.json

.gitlab-ci.yml

最後に、これまで変更したコンテナやGitLab Runnerを使用する .gitlab-ci.yml の修正をおこないます。

---
image: registry.nnstt1.work/sample/docker:19.03.11-molecule    <- (1)

variables:    <- (2)
  DOCKER_TLS_CERTDIR: "/certs"
  HTTP_PROXY: http://proxyserver:proxyport
  HTTPS_PROXY: http://proxyserver:proxyport
  NO_PROXY: docker

services:    <- (3)
  - name: registry.nnstt1.work/sample/docker:19.03.11-dind
    alias: docker

before_script:    <- (4)
  - docker info
  - python3 --version
  - ansible --version
  - molecule --version
  - docker login registry.nnstt1.work

molecule:
  stage: test
  script:
    - molecule test
  1. image
    docker hub で公開されている docker:19.03.11 から、今回ビルドした docker:19.03.11-molecule コンテナイメージを使用するように変更します。 今回はGitLabに構築したプライベートレジストリ registry.nnstt1.work 上にコンテナイメージを格納しています。

  2. variables
    HTTP_PROXYHTTPS_PROXY にプロキシサーバを指定します。
    NO_PROXY にはプロキシを経由しないIPアドレスやホスト名を指定しますが、今回は docker としています。 これは下記のservicesで指定した alias と同じ文字列にする必要があります。

  3. services
    imageと同じように今回ビルドした docker:19.03.11-dind コンテナイメージを指定しますが、加えて name というキーを指定します。 また、alias キーで docker という文字列を指定します。
    servicesで alias を指定していない場合、ビルドコンテナからサービスコンテナにアクセスするためのホスト名は、リポジトリURL+コンテナイメージ名 となります。 (詳しくはこちら) そのため、プライベートレジストリ内のコンテナイメージを指定した場合は、registry.nnstt1.work__docker となります。
    しかし、alias を設定することで任意のホスト名でアクセスすることが可能になります。今回は元々使用していたコンテナイメージと同じになるように docker という文字列を指定します。この alias の設定と、上記の NO_PROXY の設定によって、ビルドコンテナからプロキシを経由せずに docker という名前でサービスコンテナ(dind)にアクセスが可能となります。

  4. before_script
    Moleculeインストール済みのコンテナイメージを使用するようにしたため、元々あったMoleculeをインストールコマンドは削除しています。 また、Molecule実行時にプライベートレジストリのコンテナを使用するため、docker login コマンドを追加しています。

まとめ

上記の手順でなんとか社内のGitLabでMoleculeを動かすことができました。これで職場でも継続的にPlaybookやRoleのテストができるようになりました。

しかし、これはあくまでも準備段階の話です。Moleculeを活かすには、しっかりとテストを用意する必要があります。テスト作るの苦手ですが滅気ずにがんばります。