変更した `coredns` の docker image を作ってみる

27487 ワード

Ubuntu に Docker を install する

まずは Docker を install する。
これ を見て作業する。

$ sudo apt-get update

$ sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

$ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

$ sudo apt-get update

$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

んで、動作確認がてら hello-world を実行しておきます。

$ sudo docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

corednsmake する

つぎに ここ を見ながら CoreDNS の環境を整えていく。

$ git clone https://github.com/coredns/coredns
$ cd coredns

のあと、golang を install してもいいんですがめんどいので、

$ docker run --rm -i -t -v $PWD:/v -w /v golang:1.17 make

でしばらく待ってると coredns という binary が完成するのでそれが楽ちんです。
コマンドの簡単な説明としては以下のとおりです。

  • --rm は作業が終わったら conainter の削除
  • -i -t はまとめて -it でもいいけど tty 使えるようにするやつ、たぶん
  • -v $PWD:/v で、$PWD つまり cd coredns した後のディレクトリを volume として /v ディレクトリに mount する
  • -w /v でその /v を working directory として run する
  • golang:1.17 make で実際に make される
  • mount して実行してるので、元の世界側に make した binary が落ちてる

すっごい簡単でよいですね。

Dockerfile を編集する

次にこの coredns を込めた docker image を作成していきます。
もともとの repository に Dockerfile があるので、これを適当に編集していきます。

元の内容がこれで、multi-stage build を利用しているようです。

FROM debian:stable-slim

RUN apt-get update && apt-get -uy upgrade
RUN apt-get -y install ca-certificates && update-ca-certificates

FROM scratch

COPY --from=0 /etc/ssl/certs /etc/ssl/certs
ADD coredns /coredns

EXPOSE 53 53/udp
ENTRYPOINT ["/coredns"]

たぶん、こういう感じの作業のはず。

  • /etc/ssl/certs にはルート証明書がいっぱいあるので、それを最新化するために update-ca-certificates を実行してる
  • コンテナ自体のサイズは最小化したいので FROM scratch でまっさらイメージから coredns の binary だけを COPY した docker image を用意する

で、このままだとセキュリティレベルの高い、ただしデバッグがしづらい docker image になっています。具体的には kubectl exec -it -- bash すらできません。

$ kubectl exec coredns-xxxxxxxxx-xxxxx -n kube-system -- bash
error: Internal error occurred: error executing command in container: failed to exec in container: failed to start exec "a364eb42b1e435ff3290bb64b5249dea9f84a2a8a7ad3f8c94ea4639787c42c7": OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: "bash": executable file not found in $PATH: unknown

これに関しては kubectl debug とかの手段もあるんですが、今回は別の方法でやろうと思って進めています。

そこで、2nd stage (?) を FROM debian:stable 等に変えて、もうちょい汎用的な base image から docker image を作るように変えます。

FROM debian:stable-slim

RUN apt-get update && apt-get -uy upgrade
RUN apt-get -y install ca-certificates && update-ca-certificates

FROM debian:stable

COPY --from=0 /etc/ssl/certs /etc/ssl/certs
ADD coredns /coredns

EXPOSE 53 53/udp
ENTRYPOINT ["/coredns"]

ACR を作成し、AKS と関連付ける

ここで、別途 ACR (Azure Container Registry) を作っておきます。
docs を参考に手順を進めればさほど難しくないです。
試してみてちょっと違う点としては、az acr login--expose-token という option がいるかもしれないです。
あまり細かい点が分かってないんですが root 権限でないとうまくいかないので、sudo -s とかで権限上げてから az login しなおして実行しました。

$ sudo -s
# az acr login --name <acr-name> --expose-token

そのほか、AKS と ACR も接続しておきます。
こちらも docs があるので難しくないです。

具体的には 1 行で終わります。

$ az aks update -g <resource-group> -n <cluster-name> --attach-acr <acr-name>

docker image の build

んで、docker build します。docker tag をつけます。docker push します。

$ sudo docker build -t local/custom-coredns .
$ sudo docker tag local/custom-coredns <acr-name>.azurecr.io/custom-coredns:v1
$ sudo docker push <acr-name>.azurecr.io/custom-coredns:v1

docker images はこんな感じかと。
multi-stage build の中間の image が残るのが何か微妙よね。

# docker images
REPOSITORY                               TAG           IMAGE ID       CREATED        SIZE
<acr-name>.azurecr.io/custom-coredns   v1            1234c3187e81   15 hours ago   130MB
local/custom-coredns                     latest        1234c3187e81   15 hours ago   130MB
<none>                                   <none>        6fd88635894d   15 hours ago   101MB
golang                                   1.17          b6bd03a3a78e   2 weeks ago    941MB
debian                                   stable-slim   b20702a8e984   2 weeks ago    80.4MB
debian                                   stable        4c8dfa39e6ff   2 weeks ago    124MB
hello-world                              latest        feb5d9fea6a5   7 months ago   13.3kB

ConfigMap の作成

次にその ACR から Pod を作成したいんですが、その前に coredns 用の ConfigMap を用意しておきます。
中身は 2 つありますが、2 つめのは中身はありません。
1 つ目についてもいろいろ書いてありますが基本的には $ kubectl get cm coredns -n kube-system -o yaml の内容を踏襲してます。

$ cat custom-coredns-configmap.yaml | sed 's/........-....-....-....-\(............\)/xxxxxxxx-xxxx-xxx
x-xxxx-\1/g'
apiVersion: v1
data:
  Corefile: |
    .:53 {
        errors
        ready
        health
        kubernetes cluster.local in-addr.arpa ip6.arpa {
          pods insecure
          fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
        import custom/*.override
    }
    import custom/*.server
kind: ConfigMap
metadata:
  annotations:
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
    k8s-app: kube-dns
  name: coredns
---
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    addonmanager.kubernetes.io/mode: EnsureExists
    k8s-app: kube-dns
  name: coredns-custom

まずはこちらを kubectl apply します。
corednscoredns-custom というのがあれば大丈夫です。

$ kubectl apply -f custom-coredns-configmap.yaml

$ kubectl get cm
NAME               DATA   AGE
coredns            1      14h
coredns-custom     0      14h
kube-root-ca.crt   1      18h

Pod の作成

次に pod 用の yaml を書きます。
これも kubectl get po coredns-xxxxxxxxx-xxxxx -n kube-system -o yaml の結果を必要そうなところだけに削りまくったものです。

一番重要な修正点はここだけ。

  • .spec.containers.image を ACR のやつに

ConfigMap 関連はたぶん以下の雰囲気のはず。

  • args-conf /etc/coredns/Corefile と書いてあるのでこれが option として指定されて pod が起動する
  • それは volumeMountsmount されることになっている
  • で、それは volumes のところで ConfigMap で実現されている
  • そのために事前に ConfigMap を用意している
$ cat custom-coredns-pod.yaml | sed 's/........-....-....-....-\(............\)/xxxxxxxx-xxxx-xxxx-xxxx
-\1/g'
apiVersion: v1
kind: Pod
metadata:
  labels:
    k8s-app: kube-dns
  name: custom-coredns
spec:
  containers:
  - args:
    - -conf
    - /etc/coredns/Corefile
    env:
    - name: KUBERNETES_PORT_443_TCP_ADDR
      value: private-cl-aks-20220504-81d00f-feda6be9.xxxxxxxx-xxxx-xxxx-xxxx-c5c05e4746d6.privatelink.southeastasia.azmk8s.io
    - name: KUBERNETES_PORT
      value: tcp://private-cl-aks-20220504-81d00f-feda6be9.xxxxxxxx-xxxx-xxxx-xxxx-c5c05e4746d6.privatelink.southeastasia.azmk8s.io:443
    - name: KUBERNETES_PORT_443_TCP
      value: tcp://private-cl-aks-20220504-81d00f-feda6be9.xxxxxxxx-xxxx-xxxx-xxxx-c5c05e4746d6.privatelink.southeastasia.azmk8s.io:443
    - name: KUBERNETES_SERVICE_HOST
      value: private-cl-aks-20220504-81d00f-feda6be9.xxxxxxxx-xxxx-xxxx-xxxx-c5c05e4746d6.privatelink.southeastasia.azmk8s.io
    image: <acr-name>.azurecr.io/custom-coredns:v1.1
    imagePullPolicy: IfNotPresent
    name: custom-coredns
    ports:
    - containerPort: 53
      name: dns
      protocol: UDP
    - containerPort: 53
      name: dns-tcp
      protocol: TCP
    volumeMounts:
    - mountPath: /etc/coredns
      name: config-volume
      readOnly: true
    - mountPath: /etc/coredns/custom
      name: custom-config-volume
      readOnly: true
    - mountPath: /tmp
      name: tmp
  restartPolicy: Always
  volumes:
  - configMap:
      defaultMode: 420
      items:
      - key: Corefile
        path: Corefile
      name: coredns
    name: config-volume
  - configMap:
      defaultMode: 420
      name: coredns-custom
      optional: true
    name: custom-config-volume
  - emptyDir: {}
    name: tmp

あとは kubectl apply するだけですね。

$ kubectl apply -f custom-coredns-pod.yaml

この pod であれば kubectl exec -it -- bash ができます。

$ k exec -it custom-coredns -- bash
root@custom-coredns:/#

localhostcoredns が DNS cache server として動いてるはずなので dig で簡単に確認しておきましょう。

# apt-get update
# apt-get install dnsutils
# dig @localhost www.microsoft.com. +short
www.microsoft.com-c-3.edgekey.net.
www.microsoft.com-c-3.edgekey.net.globalredir.akadns.net.
e13678.dscb.akamaiedge.net.
104.83.197.169

とりあえずここまで。