[sbt]sbt-native-packagerのdocker:publishでGitLabのRegistryへのアップロードがGitLabCI-Runner経由だとアクセス拒否される

# 起きた事
sbt-native-packagerを使って開発しているsbtプロジェクトがある
dockerプラグインを入れ、イメージの作成とpushは `docker:publish` で行なっている
ローカルからの実行だと問題なく成功する

```java
...

[info] Successfully tagged hoge/fuga/nyanyanya/scala:latest
[info] Built image hoge/fuga/nyanyanya/scala:latest
[info] The push refers to repository [hoge/fuga/nyanyanya/scala]
[info] 123456789abc: Preparing
[info] 123456789abc: Preparing
[info] 123456789abc: Preparing
[info] 123456789abc: Waiting
[info] 123456789abc: Waiting
[info] 123456789abc: Waiting
[info] 123456789abc: Pushed
[info] Published image hoge/fuga/nyanyanya/scala:latest
[success] Total time: 23 s, completed 2019/04/05 12:54:49
```

これをciからのスクリプト実行で経由した場合、失敗する。
事前にdocker loginは実施済み

`ci/script/build_push_docker_at_dev.sh` は、 GCPやGitlabに対してアップロードしている記述をまとめたスクリプト。内部で `docker:publish` を行なっている

```gitlab-ci.yml
create-docker-image:
  image: ******
  stage: create-docker-image
  when: manual
  script:
    - docker login -u ******* -p ******* "$CI_REGISTRY"
    - sh ./ci/script/build_push_docker_at_dev.sh
```

ci実行

```java

Running with gitlab-runner ...
Skipping Git submodules setup

$ docker login -u ******* -p ******* "$CI_REGISTRY"
Login Succeeded

$ sh ./ci/script/build_push_docker_at_dev.sh
Loading project definition from /builds/hoge/fuga ~~
[info] Resolving com.typesafe.play#sbt-plugin;2.5.10 ...

...

[info] Successfully tagged hoge/fuga/nyanyanya/scala:latest
[info] Built image hoge/fuga/nyanyanya/scala:latest
[info] The push refers to repository [hoge/fuga/nyanyanya/scala]
[info] 123456789abc: Preparing
[info] 123456789abc: Preparing
[info] 123456789abc: Preparing
[info] 123456789abc: Waiting
[info] 123456789abc: Waiting
[info] 123456789abc: Waiting
[error] denied: access forbidden
[error] (docker:publish) Nonzero exit value: 1
[error] Total time: 31 s, completed Apr 5, 2019 1:59:20 PM
```

gitlab-ci経由だとアクセス拒否される

# やりたい事（適当）
![スクリーンショット 2019-04-05 20.04.46.png](https://qiita-image-store.s3.amazonaws.com/0/178351/21a66208-712e-82af-0c1d-925524d090d0.png)

# 調査
sbtのdocker:publishではなく通常のpushコマンドを追加してみる（これでそもそもログインできていないのか、docker:publishの問題なのか切り分けができる）

```dockerfile
 docker-compose build test
 docker-compose push test
```

```java

Running with gitlab-runner ...
Skipping Git submodules setup

$ docker login -u ******* -p ******* "$CI_REGISTRY"
Login Succeeded

$ docker-compose build test
Building test
Step 1/2 : FROM centos7
 ---> 123456789abc
Step 2/2 : ENV TZ Asia/Tokyo
 ---> Using cache
 ---> 123456789abc
Successfully built 123456789abc
[info] Successfully tagged hoge/fuga/nyanyanya/test:latest
[info] Built image hoge/fuga/nyanyanya/test:latest

$ docker-compose push test
[info] The push refers to repository [hoge/fuga/nyanyanya/scala]
latest: digest: sha256:123456789..... size: 2404
```

こちらは問題なくpushができた
-> ユーザーのログイン自体には成功していて、pushも通常記述であれば突破できている
  -> sbt側の問題

# 問題が起きるパターン
* gitlab-runner上
* sbt-native-packagerのdockerpluginで操作
* docker:publishでbuild -> pushを行なった時に、push時にアクセス拒否される

# 原因調査
### 構文エラーは無いか？

そもそもローカルだと通っているので、構文のミスは無いと考えれる
Runnerで動かした時にdocker loginの情報が渡されていないのがおかしい
本来は渡されると公式に明記されている

> docker:publish
ローカルのDockerサーバーを使ってイメージを構築し、それを設定済みのリモートリポジトリにプッシュします。

docker loginを実行 -> sbt docker:publish の順番であれば本来ログイン情報は引き継がれる（ローカルだと引き継がれている）

### 指定先が間違えていないか？

> dockerRepository
docker:publishタスクが実行されたときにイメージがプッシュされるリポジトリ。これは[repository.host[:repository.port]]（index.docker.ioリポジトリの使用を想定して）または[repository.host[:repository.port]][/username]（推奨されていませんが、後方互換性のために利用可能です）の形式であるべき です。


-> ログ的に今回pushしたいレジストリへの指定は間違っていなさそうだ

```build.sbt
dockerRepository := Some("hoge/fuga/nyanyanya")

# ログ
[info] The push refers to repository [hoge/fuga/nyanyanya/scala]
```

### ユーザーが切り替わっていないか？

> dockerUsername
docker:publishタスクが実行されたときにイメージがプッシュされるユーザー名または組織。これは、フォームでなければなりません[username]か[organization]。

私のプロジェクトではこれを指定していなかった。これを指定してみる

記述参考はgithubで適当に検索したら出てきたこの人のを使わせてもらった
https://github.com/gemini-hlsw/itc-server/blob/a79ae7c639d8bb209d49844fd8a6a261c59011a0/build.sbt

```build.sbt
      dockerUsername := Some("********"),
```

```build.sbt

error: not found: value dockerUsername
      dockerUsername := Some("********"),
      ^
sbt.compiler.EvalException: Type error in expression
```

Keys.scalaになかったので手動追加

```build.sbt
lazy val dockerUsername = SettingKey[Option[String]]("dockerUsername", "Username for published Docker image")
```

実行するもエラー変わらず

### docker:publishを諦める

`docker:publishLocal` でイメージの作成までは行えるため、ここまで行い push を別タスクとして実行すればいける説

> docker:publishLocal
ローカルのDockerサーバーを使って画像を作成します。

pushでコケてしまい、sbt側でしたいのはbuildまでなので分けてみる

```java

java $SBT_OPTS -jar `dirname $0`/sbt-launch-0.13.12.jar "$@"; exit $? # docker:publishLocal
docker push hoge/fuga/nyanyanya/scala:↑で発行したタグ
```

```java
[error] denied: access forbidden
```

えぇ…

どうやらsbt側の問題ではなかった模様。意味不明

# 原因整理

### これは通る

```java
 docker-compose build test
 docker-compose push test
```

### これは通らない

```java

java $SBT_OPTS -jar `dirname $0`/sbt-launch-0.13.12.jar "$@"; exit $? # docker:publish

or

java $SBT_OPTS -jar `dirname $0`/sbt-launch-0.13.12.jar "$@"; exit $? # docker:publishLocal
docker push hoge/fuga/nyanyanya/scala:↑で発行したタグ
```

docker-composeでpushは通るけどdockerのpushができていない

dockerコマンドが何かしら悪いという結論に落ち着いた

dockerだとgitlab-ci.ymlでログインした情報を引き継がない？（考えづらいが。。。）

同じ現象に陥っている、気になるIssueを見つけた
https://gitlab.com/gitlab-org/gitlab-ce/issues/37861

この中の記述によるとDockerのバージョンをあげれば直ったとの事
ちなみに私のRunnerの実行imageは自前で作り、バージョンは指定していなかった

```dockerfile
FROM centos:centos7

RUN yum update -y && \
    yum install -y wget tar java-1.8.0-openjdk java-1.8.0-openjdk-devel && \
    yum install -y docker && \
...
```

これは怪しいぞ・・・　バージョンを確認してみる

```dockerfile
$ docker exec -it 123456789abc /bin/bash

$ docker -v
Docker version 1.13.1, build b2f74b2/1.13.1
```

これはダメかもしれない。。。。。かなり古いやつ使ってました
これはローカルとRunnerで実行差が出るのが納得できてしまう
ローカルは `18.09.1` でした。ほぼ最新

バージョンをあげ直して再チャレンジ

```dockerfile
RUN yum install -y yum-utils device-mapper-persistent-data lvm2 && \
    yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo && \
    yum install -y docker-ce

# version確認
RUN docker -v
```

```java

Step 9/9 : RUN docker -v
 ---> Running in 123456789abc
Docker version 18.09.4, build 123456789abc
```

Issueでの解決したバージョンと同じ 18.09 をインストール。

という事でバージョンアップの手順をDockerfileに追記し、dockerをアップデートしたimageを使って再度Runner実行

```shell

$ docker build --no-cache -f ./ci/dockerfile/Dockerfile-build-base-image ./ -t registry.hoge.fuga/nyanyanya
Successfully built 123456789abc
Successfully tagged registry.hoge.fuga/nyanyanya:latest

$ docker push registry.hoge.fuga/nyanyanya
```

```gitlab-ci.yml
create-docker-image:
  image: "$CI_REGISTRY_IMAGE/nyanyanya:latest" # ここにさっき作ったimageを指定
  stage: create-docker-image
  when: manual
  script:
    - docker login -u ******* -p ******* "$CI_REGISTRY"
    - sh ./ci/script/build_push_docker_at_dev.sh
```

`docker:publish` に直しておいて再度CI実行

```java

[info] Successfully tagged hoge/fuga/nyanyanya/scala:latest
[info] Built image hoge/fuga/nyanyanya/scala:latest
[info] The push refers to repository [hoge/fuga/nyanyanya/scala]
[info] 123456789abc: Preparing
[info] 123456789abc: Preparing
[info] 123456789abc: Preparing
[info] 123456789abc: Waiting
[info] 123456789abc: Waiting
[info] 123456789abc: Waiting
[info] 123456789abc: Pushed
[info] Published image hoge/fuga/nyanyanya/scala:latest
[success] Total time: 36 s, completed Apr 5, 2019 9:43:14 PM
```

通りました。問題はdockerだった

# 結論
原因はdockerのバージョンが古すぎた事

yumでバージョン指定せずに適当に入れると古いdockerが入り込み失敗するので気をつけよう！！
sbtは何一つ関係ない

これに気づくのに2日使ってしまって辛い 😂😂