GitlabのコンテナレジストリのバックエンドをAzureのBLOBにしてRunner入れてつかってみる

ちょっとながくなった。
GWのスキマの営業日に人がいないであろうと移行作業したついでに色々やりたかった備忘録の一部です。
移行自体はまあ収まったのですがここに書いてるやつはだいぶGWはみでました。まあしょうがない。
この記事より公式のマニュアル見るのをお勧めしたい。これはただの備忘録です。

### AzureBlobにコンテナを作る
ポータルからポチポチでもいけます。ストレージアカウントなければ作るところから。
権限はプライベートで大丈夫。
[Using the Azure CLI 2.0 with Azure Storage | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/storage/common/storage-azure-cli)
[AzureのBlobに定期バックアップファイルを投げ込む](https://qiita.com/smallpalace/items/7b738ecfb6782d121f75)

### dockerいれて起動する

```yaml
---
# install docker
- stat:
    path: /bin/docker
  register: chk_docker
- name: install docker
  shell: /usr/bin/curl -sSL https://get.docker.com/ | sudo sh
  when: not chk_docker.stat.exists
- name: run docker
  service:
    name: docker
    state: started
    enabled: yes
```
雑ですみませんがansibleタスクだけ置いときます

### gitlab.rbを設定してreconfigureする
gitlab自体は普通にyumでいれたものでホストOS上で稼働している前提です。
プライベートコンテナレジストリ用SSL証明書はgitlab本体と一緒という体で失礼します。
registry_external_urlに本体のURLにポート足した設定します。
で、本体に指定してる証明書と同じものを指定します。
ドメイン変える場合は別途その証明書がいります。

```conf:/etc/gitlab/gitlab.rbの一部
registry_external_url 'https://my-gitlab-domain:5005'
registry['storage'] = {
  'azure' => {
    'accountname' => 'mystorageaccount',
    'accountkey' => '***storageaccount-key***'
    'container' => 'container-name'
  }
}
registry_nginx['ssl_certificate'] = "/etc/letsencrypt/live/my-gitlab-domain/fullchain.pem" 
registry_nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/my-gitlab-domain/privkey.pem" 
```

さんこう
http://docs.gitlab.com/ce/administration/container_registry.html#container-registry-storage-driver
https://docs.docker.com/registry/configuration/#storage
https://github.com/docker/docker.github.io/blob/master/registry/storage-drivers/azure.md

```shell-session
# gitlab-ctl reconfigure
# gitlab-ctl status
```
上記で設定を反映する
### docker loginしてつかってみる

設定すると各プロジェクト毎のメニューにRegistryというリンクが増えてて以下のようなURLにアクセスすると
`https://my-gitlab-domain/namespace/project-name/container_registry`

以下のような説明がでてるのでそのとおりに。

```
## A 'container image' is a snapshot of a container. You can host your container images with GitLab. 
## To start using container images hosted on GitLab you first need to login:

docker login my-gitlab-domain:5005

## Then you are free to create and upload a container image with build and push commands:

docker build -t my-gitlab-domain:5005/namespace/project-name .

docker push my-gitlab-domain:5005/namespace/project-name
```

ログインするとき聞かれるユーザ名とパスワードはgitlabにログインするときと同じ。二段階認証してる場合はトークンをパスワードに指定するかんじです。（ローカルの設定ファイル`~/.docker/config.json`に書かれる）
外部認証でログインしている場合にパスワードが未設定な状態となりパスワードを設定するまで docker login ができない。

### hubからコピってpushしてみる
試すだけなのでなんでもいいのですがとりあえずmysql8.0のイメージをさがしてpullってpushしてみます。
（本来はプロジェクトの成果物をビルドするかテストに使うなにかをビルドしてpushしておくという話だと思います。）

```shell-session
# docker login my-gitlab-server:5005
# docker search mysql
NAME                                                   DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
mysql                                                  MySQL is a widely used, open-source relation…   6150                [OK]                
mariadb                                                MariaDB is a community-developed fork of MyS…   1928                [OK]                
～略～
# docker pull mysql:8.0.11
8.0.11: Pulling from library/mysql
f2aa67a397c4: Pull complete 
1accf44cb7e0: Pull complete 
～略～
# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mysql               8.0.11              a8a59477268d        4 days ago          445MB

# docker tag mysql:8.0.11 my-gitlab-server:5005/namespace/project-name
# docker images
REPOSITORY                                                 TAG                 IMAGE ID            CREATED             SIZE
mysql                                                      8.0.11              a8a59477268d        4 days ago          445MB
my-gitlab-server:5005/namespace/project-name               latest              a8a59477268d        4 days ago          445MB

# docker push my-gitlab-server:5005/namespace/project-name
```
registryにあがってるかWebUIからプロジェクト別のregistryを確認する。
（上がってたやつはlatestという名前になってた。タグつけないとそうなる模様。タグ付けるとその名前がWebUI上でNameとなる）
azureのBlob側のコンテナも見るとなんかプロジェクトのフォルダが挟まったファイルができていた。
要らない場合とりあえずWebUIからゴミ箱マークを押すと消せる。（同じIDのやつ全部消える）
pushしたイメージを起動する場合、
`docker run my-gitlab-server:5005/namespace/project-name`などで起動できる。

ちなみにrakeでバックアップつくるときにローカルのregistyだとそのバックアップアーカイブが別にできるんですがバックエンドストレージを指定してる場合はそれが作られないようでした。（ので別の仕組みでスナップショットでもとっとけというようなことがマニュアルに書かれていました）

https://qiita.com/ynott/items/585b7810d71d949e9072
https://qiita.com/masakura/items/802f4b8ce322d2543c80

### multi-runnerいれる（CIなんとかしてみる）
別のホストにgitlab-runner（CIするやつなのでサーバリソース食い合わないようにホスト自体を分離）を入れる。
jobの実行にdocker-executorが使えたほうが便利そうなのでdockerも入れる。

```yaml:roles/ommunibus-gitlab-ci/tasks/main.yml
# install gitlab runner.
---
# for docker executer
- stat:
    path: /bin/docker
  register: chk_docker

- name: install docker
  shell: /usr/bin/curl -sSL https://get.docker.com/ | sudo sh
  when: not chk_docker.stat.exists

# install gitalb-runner

- name: install gitlab repo
  yum_repository:
    name: runner_gitlab-ci-multi-runner
    description: runner_gitlab-ci-multi-runner
    file: runner_gitlab-ci-multi-runner
    baseurl: "https://packages.gitlab.com/runner/gitlab-ci-multi-runner/el/7/$basearch"
    repo_gpgcheck: yes
    gpgcheck: no
    enabled: yes
    gpgkey: "https://packages.gitlab.com/runner/gitlab-ci-multi-runner/gpgkey"
    sslcacert: '/etc/pki/tls/certs/ca-bundle.crt'
    sslverify: yes
    metadata_expire: 300
  tags: runner-repo

- name: install gitlab-runner package
  yum:
    name: gitlab-ci-multi-runner-1.11.1-1.x86_64
    state: present
```
本体gitlab（現状8.13.4）に合わせるとrunnerのバージョンは`gitlab-ci-multi-runner-1.11.1-1.x86_64`でないとだめっぽいです。


https://github.com/ayufan/gitlab-ci-multi-runner

入れると起動してイメージが入っていた

```shell-session
# ps -ef|grep runner
root      56681  56591  0 10:01 pts/0    00:00:00 grep --color=auto runner
root      71078      1  0 May08 ?        00:03:16 /usr/bin/gitlab-ci-multi-runner run --working-directory /home/gitlab-runner --config /etc/gitlab-runner/config.toml --service gitlab-runner --syslog --user gitlab-runner

# docker images
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
gitlab/gitlab-runner-helper   x86_64-a67a225      469cc8183675        23 hours ago        38.8MB
gitlab/gitlab-runner          latest              182563d7f653        6 days ago          360MB

```

### WEBUIからプロジェクト毎のトークンを確認する

AdminエリアのRunnersにtokenがあるのでそれをコピーする。

あとプロジェクト毎のトークンをプロジェクトのページの歯車＞CI/CDpipeline、から入手してrunner登録も可能な模様

### gitlab-ci-multi-runner registerでrunnerを登録する

```
# gitlab-ci-multi-runner register
Running in system-mode.                            
                                                   
# gitlabサーバのURLを入力する
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://my-gitlab-server/ci  
Please enter the gitlab-ci token for this runner:
****ここにtokenをはる****
# runnerのhostが識別できるように説明を入力（ホスト名が表示されてるのでEnter)
Please enter the gitlab-ci description for this runner:
[myhost02]: 
# gitlab上でrunnerの見分けがつくように適当なタグを入力
Please enter the gitlab-ci tags for this runner (comma separated):

# runnerの実行環境を入力します
# ここではdockerを選択
Please enter the executor: docker+machine, docker-ssh+machine, docker, docker-ssh, parallels, shell, ssh, virtualbox:
docker

# runnerでつかうデフォルトイメージを指定
ubuntu:xenial
```


```
##設定こんなかんじになってた
# cat /etc/gitlab-runner/config.toml 
concurrent = 1
check_interval = 0

[[runners]]
  name = "myhost02"
  url = "https://my-gitlab-server/ci"
  token = "033b6640ccbaaae*****"
  executor = "docker"
  [runners.docker]
    tls_verify = false
    image = "ubuntu:xenial"
    privileged = false
    disable_cache = false
    volumes = ["/cache"]
  [runners.cache]
```

-nと他の必須オプション指定すると非対話にできるっぽい
あとprivileged = trueじゃないとservicesとしてコンテナ指定ができなさそうなことがマニュアルに書いてあった。
see:`gitlab-runner register --help`

```
gitlab-runner register -n \
>     --url https://my-gitlab-server/ci \
>     --registration-token "$gitlab_ci_token" \
>     --name myhost02 \
>     --tag-list docker,shell \
>     --executor docker,shell \
>     --docker-image alpine:latest
```

executerという実行環境については以下がえらべる。
kubernetes, docker, parallels, ssh, virtualbox, docker-ssh+machine, docker-ssh, shell, docker+machine
DockerExecuterつかうならDockerのv1.5.0以上をいれデフォルトイメージ選択しとかないとでSSHするなら接続情報と鍵が要るなど。

https://docs.gitlab.com/runner/executors/docker.html
https://docs.gitlab.com/runner/executors/README.html


### プロジェクト直下に.gitlab-ci.ymlを置く
プロジェクトに登録されてるファイルつかってスクリプト動かすとかyamlに書くことができるようです。これに書くとpushしたらそれが動くようにできる。
.gitlab-ci.ymlのかきかた↓
https://docs.gitlab.com/ce/ci/yaml/README.html
https://docs.gitlab.com/runner/commands/README.html#limitations-of-gitlab-runner-exec

|項目|説明|
|:--|:--|
|script|Runner上で実行されるスクリプトやコマンドを指定|
|image|コンテナを利用するExecutorのDockerイメージを指定|
|service|コンテナを利用するExecutorのDockerサービスを指定|
|stage|ジョブのステージ設定|
|variables|ジョブ内で利用される変数定義|
|only|指定したブランチ、タグの更新があった場合のみジョブを実行|
|except|指定した以外のブランチ、タグの更新があった場合のみジョブを実行|
|tags|実行するRunnerのタグを指定|
|allow_failure|失敗を許可するかどうかを指定|
|when|特定の条件にマッチした場合のみジョブを実行|
|dependencies|成果物をほかのジョブ間で受け渡す際の指定|
|artifacts|ジョブの成果物の保存を定義|
|cache|プロジェクトワークスペース内のパスを使いジョブ間のファイルキャッシュリストを指定|
|before_script|scriptの前に行うタスクを定義|
|after_script|scriptの後に行うタスクを定義|
|retry|ジョブ失敗しても動的にリトライする回数を指定|

簡単なテストならこんなん↓で動くみたいですね。
やりたい内容をbuild.shみたいなスクリプトに全部定義して置いといてそれを動かすだけとかでもよさそう。

```
test:
  script: echo "hello world"
```

なにがしたいかというとdockerコンテナつくってansible-playbookが実行されてテストの履歴とテスト済みのリポジトリが残るとマージリクエストの根拠としていいなとおもいました。で、それをするのにexecuterはdockerが便利かなっておもいました。（VMいちいち作るオーバヘッドがないしシェルだとまあ冪等の確認はできるんだろうけど環境を戻す手間が尋常じゃないよなあ等）

GitLab-CIではservices内にDockerイメージを記載することで、CI実行中にテスト実行用のコンテナとは別にコンテナを動かすことが出来る、らしいのでcentos7でsshできるイメージを生成してそのイメージをContainerRegistryに登録してみたりもしたんですが、↓

```
# vi dockerfile
----
FROM jdeathe/centos-ssh:centos-7

# 「rootでログインはしない」「`yum install`は使う」のために設定
ADD ./sudoers /etc/sudoers.d/
----
# cp /etc/sudoers.d/waagent .
# cat waagent
myuser ALL=(ALL) ALL
# docker build -t my-gitlab-server:5005/namespace/project-name:centos7-ssh .
Sending build context to Docker daemon  3.072kB
Step 1/2 : FROM jdeathe/centos-ssh:centos-7
 ---> ff8de4483bf6
Step 2/2 : ADD ./waagent /etc/sudoers.d/
 ---> e38bd2c32990
Successfully built e38bd2c32990
Successfully tagged my-gitlab-server:5005/namespace/project-name:centos7-ssh
# docker push my-gitlab-server:5005/namespace/project-name:centos7-ssh
# docker images
REPOSITORY                                                 TAG                 IMAGE ID            CREATED             SIZE
my-gitlab-server:5005/namespace/project-name               centos7-ssh         e38bd2c32990        3 minutes ago       219MB
jdeathe/centos-ssh                                         centos-7            ff8de4483bf6        2 weeks ago         219MB

以下に上がってることを確認
https://my-gitlab-server/namespace/project-name/container_registry

```
なんだか8系だからかプライベートコンテナレジストリにあるimageをservicesでたぶん使えないっぽいことに大分時間たってから気が付いてしまいました。（プライベートじゃなくてパブリックのイメージにしたらアッサリうまくいった）
プライベートのプロジェクトだとdocker loginするようなアカウントをsecret variables（ただしgitlab9.4からつかえる）という暗号化した変数を扱う機能で認証情報に保存できる、またはconfig.tomlに認証情報を書けるというようなのがマニュアルにのってた。ので追ってバージョンアップしたい所存。
https://docs.gitlab.com/runner/configuration/advanced-configuration.html#using-a-private-container-registry

```yaml:.gitlab-ci.yml
---
image: williamyeh/ansible:alpine3
stages:
  - lint
  - test

services:
#  - my-gitlab-server:5005/namespace/project-name:centos7-ssh
  - attakei/ansible-target:centos-7-latest

before_script:
#  - docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
  - cd tests
  - cp hosts/insecure_private_key ~/
  - chmod 400 ~/insecure_private_key

syntax_check_job:
  stage: lint
  script:
#    - ansible-playbook test.yml --syntax-check --vault-password-file=~/.vaultpass
    - ansible-playbook test.yml --syntax-check
test_job:
  stage: test
  script:
#    - ansible-playbook test.yml -D -vv --vault-password-file=~/.vaultpass
    - ansible-playbook test.yml -D -vv 
```

というわけでこんな↑感じになりましたがまだsshがpermition denyみたいな感じなので追って調べてるとこですね。
わざわざservicesでsshとかしなくてもコンテナ１個でlocalに流すだけならもうちょっとカンタンにさっと成功するかと思います。

その後8から10にバージョンアップしたりくわしい人に聞いたりしたところ、以下のようなCIのコツなどが。
→gitlab10にしたら普通に暗号化変数使えた。(変数渡すときはファイルよりはechoで環境変数にしたほうがいいらしい）
→serviceは連携する別のコンテナ（webだったらバックエンドのDBとかRedisとか）が要る場合にそのイメージを指定するものであって今回の場合はローカルに流したほうがシンプルでベストではないか
→testかくときはtaskと同じ階層にtestディレクトリをつくってそのしたにroleのテスト書くのが単体テストになっていいかんじ（統合テストが要るならそれもありだが細かいとこからテストしたほうがいい
→imageは各コンテナで指定できるため最初に指定しなくてもよくてそれぞれのジョブでCentOS7とか6とか指定できる、実際使う環境にあったイメージを使う
→相対パスとcdコマンドは避けたらほうが混乱がすくないとのこと（まあそうですよね）

まあローカルコンテナに流すやつは普通にCIできてました。

```yaml:.gitlab-ci.yml
before_script:
  - cd tests
  # - cp hosts/insecure_private_key ~/
  # - chmod 400 ~/insecure_private_key

test:centos7:
  image: centos:7
  script:
    - yum install epel-release -y -q
    - yum install ansible -y -q
    - ansible --version
    - ansible-playbook test.yml --syntax-check --vault-password-file vault.sh
    - ansible-playbook test.yml -D -vvvv --vault-password-file vault.sh
```

さらにそのご、systemdまわりが特権がないと動かないっすねーDocker in Dockerで権限ごにょごにょしないといけないのかなーみたいなことで以下のようになりました。（.job_templateというやつで隠しジョブをテンプレートにして引き継いださきで展開するかんじで同じパラメータをまとめられるということでそういう風にかいてはみた（がジョブひとつだとあんまり意味を成してはない））

```
---
image: gitlab/dind

### Test template

.job_template: &job_definition
  before_script:
    - docker pull $DOCKER_IMAGE
  script:
    - docker run --detach --volume="${PWD}":/etc/ansible/roles/role_under_test:ro --name $DOCKER_NAME $DOCKER_RUN_OPTS $DOCKER_IMAGE $DOCKER_INIT
    # Ansible sytax check
    - docker exec $DOCKER_NAME yum install epel-release -y -q
    - docker exec $DOCKER_NAME cp /etc/ansible/roles/role_under_test/tests/ansible.cfg /etc/ansible/
    - docker exec $DOCKER_NAME ansible-playbook /etc/ansible/roles/role_under_test/test.yml --syntax-check --vault-password-file /etc/ansible/roles/role_under_test/tests/vault.sh --extra-vars "$PLAYBOOK_EXTRA_VARS"
    # Test role
    - docker exec $DOCKER_NAME ansible-playbook /etc/ansible/roles/role_under_test/test.yml -D --vault-password-file /etc/ansible/roles/role_under_test/tests/vault.sh --extra-vars "$PLAYBOOK_EXTRA_VARS"

  after_script:
    - docker kill $DOCKER_NAME
    - docker rm $DOCKER_NAME

### Environments
test_centos7:
  <<: *job_definition
  stage: test
  variables:
    DOCKER_IMAGE: geerlingguy/docker-centos7-ansible:latest
    DOCKER_INIT: /usr/lib/systemd/systemd
    DOCKER_RUN_OPTS: "--privileged --volume=/sys/fs/cgroup:/sys/fs/cgroup:ro --security-opt seccomp=unconfined --cap-add=ALL"
    DOCKER_NAME: "gitlab-ci-$CI_BUILD_ID-$CI_BUILD_REF"
    PLAYBOOK_EXTRA_VARS: ""
  
### Stages/ Jobs Section

stages:
  - test
```
ただこれでもブロックファイル作ってswaponにするタスクなどはさすがにエラーで止まっていました。
https://github.com/gametize/ansible-role-aws-sdk/blob/master/.gitlab-ci.yml
https://qiita.com/ynott/items/1ff698868ef85e50f5a1
https://gitlab.com/gitlab-org/gitlab-ce/issues/20604
http://sgykfjsm.github.io/blog/2017/09/10/dockerkontenafalsezhong-desystemdwocao-zuo-sitaifalsezhu-yi-dian/
https://linuxjm.osdn.jp/html/LDP_man-pages/man7/capabilities.7.html

あと、ansible.cfgでしかrole_path指定できないけどcfgをコマンドで指定できないので所定の読まれるとこに置くしかないからマウントしてコピーしてみたいなpathまわりに地味に引っかかっていました。
注意点としてはイメージの元の説明にも書いてあったんですが、これらで用いてるイメージは使い捨てテスト用以外に用いてはならないというところでしょうか。

### 更新してpushしてCIの動作確認する

```
git push origin master
```

上にもかいたコンテナレジストリへの権限が足らなさそうなエラー以下のとおり。docker loginができてないのかなーと思って~/.docker/config.jsonを置いたりしたもののイマイチだった。

`ERROR: Preparation failed: API error (500): Get https://my-gitlab-server:5005/v2/namespace/project-name/manifests/centos7-ssh: denied: access forbidden`

誰も解決してないようなissueがあったのでとりあえず貼っておきます。。
（プライベートレジストリをservicesに指定すると起こるみたい）
https://gitlab.com/gitlab-org/gitlab-ce/issues/18973

Gitlab実践ガイドには`gitlab--ci-token`ユーザと`CI_BUILD_TOKEN`という認証されたトークンを使うとパスワード定義しなくてもログインできると書かれていました。そうだったのか。scriptsやartifactに書くほうならいけそう。
https://docs.gitlab.com/ee/ci/variables/
https://blog.n-z.jp/blog/2017-07-09-gitlab-runner.html

###8から10にした備忘録

[自分で昔書いたやつ](https://qiita.com/smallpalace/items/7c54c2d846412494e54b)をみたりなどして作業してましたが本体はともかく[runnerは本体とバージョン依存があり](https://docs.gitlab.com/runner/#compatibility-chart)まして入れなおして登録しなおしました。
パッケージとリポジトリ消して入れなおして、本体に登録してあるrunnerの登録削除して設定ファイル(/etc/gitlab-runner-config.toml)消して新たに登録しなおすだけでした。



### さんこう
https://docs.gitlab.com/runner/
https://github.com/ayufan/gitlab-ci-multi-runner
https://docs.gitlab.com/runner/executors/docker.html
https://gitlab.com/gitlab-org/gitlab-ce/issues/28941
https://qiita.com/ynott/items/1ff698868ef85e50f5a1
Gitlab実践ガイド
https://qiita.com/attakei/items/5162751598dd3e2bbb61#1-ansible-galaxy%E3%81%A7%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E3%82%BD%E3%83%BC%E3%82%B9%E4%B8%80%E5%BC%8F%E3%82%92%E6%96%B0%E8%A6%8F%E4%BD%9C%E6%88%90
https://qiita.com/ike_dai/items/834c2ad8f646366a806d
https://qiita.com/masakura/items/802f4b8ce322d2543c80#gitlab-ci-%E7%B7%A8
http://ngyuki.hatenablog.com/entry/2017/07/07/093326
https://docs.gitlab.com/ce/user/project/container_registry.html#advanced-troubleshooting
https://qiita.com/Giso_/items/1b321f7dfa6a00cfc0d7
https://qiita.com/yurano/items/a7804d987ccff37b1a9d
https://sue445.gitlab.io/gitlab-meetup-tokyo-1/#/

まさにやりたかったような組み合わせの本出るっぽいのを見かけました。
（本の情報は半年古いと聞いたので立ち読みしてから考えよう）
http://www.shoeisha.co.jp/book/detail/9784798155128