オンプレのk8sのDockerレジストリにGCRを使う

どのご家庭にも1式はあるk8sクラスタですが、コンテナイメージのレジストリ(Docker Imageを置いておくところ)をローカルにしていませんか？
ちょっとカッコ悪いので外部のDocker Registryを利用しようと思い、GCRを使ってみました。
もちろんGCRの権限でアクセスできるアカウントは設定しないとだめです。(フルオープンならいいけど。)

# TL;DR

Dockerとk8sにGCPのサービスアカウントを設定するだけ。


# Docker側

まずはdockerコマンドからGCRにpush/pullできるようにします。(pushせねばならんので書き込み権限が必要でし。

[公式イメージの push と pull
](https://cloud.google.com/container-registry/docs/pushing-and-pulling?_ga=2.106760774.-490465231.1586232625&hl=ja)を参考に。



## サーバ or デプロイ用PCにGCPのdocker認証ヘルパーを設定

dockerコマンドでgcp認証されるように設定します。

公式: [Docker 認証ヘルパーとしての gcloud](https://cloud.google.com/container-registry/docs/advanced-authentication?hl=ja#gcloud_as_a_docker_credential_helper)

```
╭─murata@deroris ~
╰─$ gcloud auth configure-docker
WARNING: Your config file at [/home/murata/.docker/config.json] contains these credential helper entries:

{
  "credHelpers": {
    "asia.gcr.io": "gcloud",
    "staging-k8s.gcr.io": "gcloud",
    "us.gcr.io": "gcloud",
    "gcr.io": "gcloud",
    "marketplace.gcr.io": "gcloud",
    "eu.gcr.io": "gcloud"
  }
}
Adding credentials for all GCR repositories.
WARNING: A long list of credential helpers may cause delays running 'docker build'. We recommend passing the registry name to configure only the registry you are using.
gcloud credential helpers already registered correctly.
```

2回目だよって言われていますけど、普通なら~/.docker/configを更新してくれます。


適当なDockerfileを作ってpushしてみます。

```
╭─murata@deroris ~/tmp/docker-reg-test 
╰─$ cat Dockerfile
FROM docker/whalesay

CMD [ "cowsay", "だいじょぶだぁ" ]%
```

まずはローカルに。

```
╭─murata@deroris ~/tmp/docker-reg-test 
╰─$ docker build -t derori/shimura/arigatou .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM docker/whalesay
 ---> 6b362a9f73eb
Step 2/2 : CMD [ "cowsay", "だいじょぶだぁ" ]
 ---> Using cache
 ---> c2c9bde3b04e
Successfully built c2c9bde3b04e
Successfully tagged derori/shimura/arigatou:latest
```

タグを付け替えます。※docker-reg-testはGCPのプロジェクト名です。

```
╭─murata@deroris ~/tmp/docker-reg-test 
╰─$ docker tag derori/shimura/arigatou gcr.io/docker-reg-test/usiro
```

詳しくは公式を参考にしてください。 公式: [イメージのレジストリへの push](https://cloud.google.com/container-registry/docs/pushing-and-pulling?hl=ja#pushing_an_image_to_a_registry)


pushします。

```
╭─murata@deroris ~/tmp/docker-reg-test 
╰─$ docker push gcr.io/docker-reg-test/usiro
The push refers to repository [gcr.io/docker-reg-test/usiro]
5f70bf18a086: Layer already exists
d061ee1340ec: Layer already exists
d511ed9e12e1: Layer already exists
091abc5148e4: Layer already exists
b26122d57afa: Layer already exists
37ee47034d9b: Layer already exists
528c8710fd95: Layer already exists
1154ba695078: Layer already exists
latest: digest: sha256:fb74e31a195246af21510c6bc7cd116abed0cb937f987705bd2eaffb4096f0f4 size: 2402
```


GCPのContainer Registryに上がってきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56925/2eb570c8-5290-48b1-0125-38629677a750.png)

上がってきていない場合には認証等が失敗しています。push時のログをちゃんと読んでみましょう。


# Kubernetes側

GCRに上がっているイメージを取ってこれるようにアカウントを設定します。(こいつは読み取りができれば事足りるハズ

secretを作成します。namespaceごとに異なるので注意です。
※`--docker-username=oauth2accesstoken`は固定です。

```
╭─murata@deroris ~/tmp/docker-reg-test 
╰─$ kubectl create secret docker-registry gcr \                                        
> --docker-server=https://gcr.io \
> --docker-username=oauth2accesstoken \
> --docker-password="$(gcloud auth print-access-token)" \
> --docker-email="$(gcloud auth list --filter=status:ACTIVE --format='value(account)')"
secret/gcr created
```

確認してみます。

```
╭─murata@deroris ~/tmp/docker-reg-test 
╰─$ kubectl describe secret/gcr
Name:         gcr
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  kubernetes.io/dockerconfigjson

Data
====
.dockerconfigjson:  568 bytes
```

できてます。
定期的にトークンの有効期限が切れるので、pullできないってログが出ていたらsecretを一回消して作り直す必要があるようです。

imagePullSecretsをするときは↑のsecretを使うように変更させます。

```
╭─murata@deroris ~/tmp/docker-reg-test 
╰─$ kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "gcr"}]}'
serviceaccount/default patched
```

これでOKなはずです。あとはPodを動かして試してみます。
ただのPodで動かせばいいので、こんな感じのマニフェストを書いてapplyしてみます。


```
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: shimura-pod
spec:
  containers:
    - name: kujira-ushiro
      image: gcr.io/docker-reg-test/usiro:latest
EOF
```


```
╭─murata@deroris ~/tmp/docker-reg-test 
╰─$ cat <<EOF | kubectl apply -f -
pipe heredoc> apiVersion: v1
pipe heredoc> kind: Pod
pipe heredoc> metadata:
pipe heredoc>   name: shimura-pod
pipe heredoc> spec:
pipe heredoc>   containers:
pipe heredoc>     - name: kujira-ushiro
pipe heredoc>       image: gcr.io/docker-reg-test/usiro:latest
pipe heredoc> EOF
pod/shimura-pod created
╭─murata@deroris ~/tmp/docker-reg-test 
╰─$ kubectl get pod
NAME          READY   STATUS             RESTARTS   AGE
shimura-pod   0/1     CrashLoopBackOff   1          8s
╭─murata@deroris ~/tmp/docker-reg-test 
╰─$ kubectl logs shimura-pod
 _______________________
< だいじょぶだぁ >
 -----------------------
    \
     \
      \
                    ##        .
              ## ## ##       ==
           ## ## ## ##      ===
       /""""""""""""""""___/ ===
  ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
       \______ o          __/
        \    \        __/
          \____\______/
```

ちゃんと動きました。


# まとめ


これでローカルにDockerレジストリを配置する必要がなくなりました。サーバの入れ替えが捗りますね。
もりもりOSを入れなおしましょう！

k8sのクラスタを作ったはいいけど、イメージの保存先に困っているあなた向けです。ほかのクラウドサービスでもコンテナレジストリはだいたいあると思いますので、この際利用してみるといいと思います！（思います！