TechFULの中の人

TechFULスタッフ・エンジニアによる技術ブログ。IT関連のことやTechFULコーディングバトルの超難問の深掘り・解説などを毎週更新

ubuntu20.04のローカルkubernatesでプライベートGCRのイメージを利用する

はじめに

444エンジニアの久保田です。 当社サービスのTechFULのバックエンドにGKEを使っています。GKEはGoogleさんがよろしくやってくれているのでk8sをよく知らなくても使い始められてしまいます。とてもありがたいのですが、ちょっとした試験するにいちいちクラウドにデプロイとかしたくないので、ローカルにk8sの試験環境を作ることにしました。ローカルでk8sを構築する簡易な手段としてminikubeやmicrok8sがあります。

わたしは普段Ubuntuを使っているので、今回はubuntu20.04でminikubeを構築します。

VirtualBoxのインストール

minikubeは仮想マシンとして HyperVisor やVirtualBox のほか、Dockerなどのコンテナでもインストールできます。今回は私が使い慣れたVirtualBoxで構築してみます。

 sudo apt-get install virtualbox

minikubeのインストール

以下のサイトのまま

https://minikube.sigs.k8s.io/docs/start/

curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_latest_amd64.deb
sudo dpkg -i minikube_latest_amd64.deb

kubectlのインストール

k8sCLIであるkubectlもインストールしておきます。

sudo snap install kubectl --classic

minikubeクラスタの構築

k8sクラスタをローカル環境で立ち上げます。クラスタと言いつつ1台構成です。今回はVirtualBoxで構築するので以下のコマンドになります。ちなみに他の端末からもアクセス可能としたい場合は --apiserver-ips=192.168.100.100 とかHOST側OSのIPアドレスを指定しておきます。 minikube start --driver=virtualbox --apiserver-ips=10.252.61.218 ちなみにminikubeのクラスタのメモリ割当のデフォルト値は2GByte、CPU割当のデフォルト値は2コアですこちらを変更する場合は以下のように指定します。

minikube start --memory='16g' --cpus=12

しばらくするとクラスタが立ち上がります。minikubeは同時にkubectlの接続情報も初期化してくれます。以下のコマンドを実行してクラスタのノードの状態を見てみましょう。

$ kubectl describe nodes
Name:               minikube
Roles:              control-plane,master
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/arch=amd64
                    kubernetes.io/hostname=minikube
                    kubernetes.io/os=linux
                    minikube.k8s.io/commit=15cede53bdc5fe242228853e737333b09d4336b5
                    minikube.k8s.io/name=minikube
                    minikube.k8s.io/updated_at=2021_05_07T18_18_42_0700
                    minikube.k8s.io/version=v1.19.0
                    node-role.kubernetes.io/control-plane=
                    node-role.kubernetes.io/master=
Annotations:        kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
                    node.alpha.kubernetes.io/ttl: 0
                    volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp:  Fri, 07 May 2021 18:18:39 +0900
Taints:             <none>
Unschedulable:      false
Lease:
  HolderIdentity:  minikube
  AcquireTime:     <unset>
  RenewTime:       Fri, 07 May 2021 20:09:39 +0900
Conditions:
  Type             Status  LastHeartbeatTime                 LastTransitionTime                Reason                       Message
  ----             ------  -----------------                 ------------------                ------                       -------
  MemoryPressure   False   Fri, 07 May 2021 20:05:24 +0900   Fri, 07 May 2021 18:18:37 +0900   KubeletHasSufficientMemory   kubelet has sufficient memory available
  DiskPressure     False   Fri, 07 May 2021 20:05:24 +0900   Fri, 07 May 2021 18:18:37 +0900   KubeletHasNoDiskPressure     kubelet has no disk pressure
  PIDPressure      False   Fri, 07 May 2021 20:05:24 +0900   Fri, 07 May 2021 18:18:37 +0900   KubeletHasSufficientPID      kubelet has sufficient PID available
  Ready            True    Fri, 07 May 2021 20:05:24 +0900   Fri, 07 May 2021 18:18:49 +0900   KubeletReady                 kubelet is posting ready status
Addresses:
  InternalIP:  192.168.99.103
  Hostname:    minikube
Capacity:
  cpu:                12
  ephemeral-storage:  17784752Ki
  hugepages-2Mi:      0
  memory:             16417908Ki
  pods:               110
Allocatable:
  cpu:                12
  ephemeral-storage:  17784752Ki
  hugepages-2Mi:      0
  memory:             16417908Ki
  pods:               110
System Info:
  Machine ID:                 b18e74ec97a54e7592a95e07c40b494f
  System UUID:                d5a90dc1-7493-bc4a-93dd-2fb45ada331f
  Boot ID:                    fbbd978a-66a6-449d-832e-033158d37314
  Kernel Version:             4.19.171
  OS Image:                   Buildroot 2020.02.10
  Operating System:           linux
  Architecture:               amd64
  Container Runtime Version:  docker://20.10.4
  Kubelet Version:            v1.20.2
  Kube-Proxy Version:         v1.20.2
PodCIDR:                      10.244.0.0/24
PodCIDRs:                     10.244.0.0/24
Non-terminated Pods:          (7 in total)
  Namespace                   Name                                CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                                ------------  ----------  ---------------  -------------  ---
  kube-system                 coredns-74ff55c5b-9d4pm             100m (0%)     0 (0%)      70Mi (0%)        170Mi (1%)     110m
  kube-system                 etcd-minikube                       100m (0%)     0 (0%)      100Mi (0%)       0 (0%)         110m
  kube-system                 kube-apiserver-minikube             250m (2%)     0 (0%)      0 (0%)           0 (0%)         110m
  kube-system                 kube-controller-manager-minikube    200m (1%)     0 (0%)      0 (0%)           0 (0%)         110m
  kube-system                 kube-proxy-5h742                    0 (0%)        0 (0%)      0 (0%)           0 (0%)         110m
  kube-system                 kube-scheduler-minikube             100m (0%)     0 (0%)      0 (0%)           0 (0%)         110m
  kube-system                 storage-provisioner                 0 (0%)        0 (0%)      0 (0%)           0 (0%)         111m
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests    Limits
  --------           --------    ------
  cpu                750m (6%)   0 (0%)
  memory             170Mi (1%)  170Mi (1%)
  ephemeral-storage  100Mi (0%)  0 (0%)
  hugepages-2Mi      0 (0%)      0 (0%)
Events:              <none>

立ち上がっていますね。

名前空間の作成

テスト用にk8sクラスタ内に名前空間を作っておきます。

kubectl create namespace test

GCR用のシークレット作成

ここからは本題です。このままではパブリックなdocker-registryからしかイメージを取得できません。実際GKEでサービス運用している場合は、GCR(Google Container Registry)のプライベートレジストリにイメージを配置していることが多いと思います。プライベートレジストリからイメージを取得するにはGCPの認証を通らなければなりません。そのためにはGCPのIAMでサービスアカウントを作成し、GCRへのアクセス権限を与え、そのサービスアカウントの認証情報をk8sの docker-registryシークレットとして登録します。

kubectl --namespace=compiler create secret docker-registry gcr-json-key \
    --docker-server=https://gcr.io \
    --docker-username=_json_key \
    --docker-password="$(cat /home/hogehoge/key.json)" \
    --docker-email=hogehoge@triple-four.com
  • gcr-json-key はシークレット名です。任意の文字列を指定してください。
  • --docker-server=https://gcr.io はプライベートレジストリのURLです。
  • ---docker-username=_json_key_json_key固定です。
  • --docker-password= は`先程作ったGCPのサービスアカウントの秘密鍵です。GoogleCloudConsoleから取得します。
  • --docker-email=hogehoge@triple-four.com は有効なメールアドレスを指定してください。

サービスアカウントの作成

次にk8sのサービスアカウントを作成します。これはk8sの世界のサービスアカウントです。上で作ったGCPのサービスアカウントとは別物と考えてください。

kubectl apply -f service_account.yml 

k8sサービスアカウントに GCR用のシークレットを紐付ける

kubectl --namespace=compiler patch serviceaccount compile-publisher -p '{"imagePullSecrets": [{"name": "staging-gcr-json-key"}]}'

おわりに

これでubuntu20.04のローカルkubernatesでプライベートGCRのイメージを利用する環境が構築できました。