🌊

helm で Harbor

15 min read

はじめに

今回はコンテナイメージを管理する Harbor についてです。
1年前にも Harbor をデプロイして試してみたのですが、Rancher の管理画面からパラメータをいれてのデプロイでした。今回は helm を使ってデプロイし、コンテナイメージを push/ pull していこうと思います。

前回の記事はこちら。

https://qiita.com/t_ume/items/1df04c1b63681d3192a3

環境情報

ubuntu:18.04.5 LTS
Kubernetes:v1.20.6
※PV に Cephを利用しています
helm:v3.5.4
docker(クライアント用):20.10

Harbor デプロイ

まずは helm にリポジトリを登録します。

# helm にリポジトリ登録
$ helm repo add harbor https://helm.goharbor.io
"harbor" has been added to your repositories

# リポジトリ登録確認
$ helm repo list
NAME            URL
harbor          https://helm.goharbor.io

# リポジトリ情報更新
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "harbor" chart repository
Update Complete. ?Happy Helming!?

# コードを取得して、values.yaml を編集する
$ helm pull harbor/harbor --untar
$ cd harbor/

# パラメータ修正で使うノードの IP を取得
$ kubectl get nodes -o jsonpath="{.items[0].status.addresses[0].address}"
192.168.10.61

パラメータ変更のため、取得した values.yaml を編集します。
今回は NodePort で公開するため、関連するパラメータを変更しています。

values.yaml
@@ -2,7 +2,7 @@
   # Set the way how to expose the service. Set the type as "ingress",
   # "clusterIP", "nodePort" or "loadBalancer" and fill the information
   # in the corresponding section
-  type: ingress
+  type: nodePort
   tls:
     # Enable the tls or not.
     # Delete the "ssl-redirect" annotations in "expose.ingress.annotations" when TLS is disabled and "expose.type" is "ingress"
@@ -22,7 +22,7 @@
     auto:
       # The common name used to generate the certificate, it's necessary
       # when the type isn't "ingress"
-      commonName: ""
+      commonName: "192.168.10.61"
     secret:
       # The name of secret which contains keys named:
       # "tls.crt" - the certificate
@@ -117,7 +117,7 @@
 # the IP address of k8s node
 #
 # If Harbor is deployed behind the proxy, set it as the URL of proxy
-externalURL: https://core.harbor.domain
+externalURL: https://192.168.10.61:30003

 # The internal TLS used for harbor components secure communicating. In order to enable https
 # in each components tls cert files need to provided in advance.

早速デプロイします。

# namespace 作成
$ kubectl create ns harbor

# harbor デプロイ
$ helm install harbor -n harbor -f values.yaml harbor/harbor
NAME: harbor
LAST DEPLOYED: Sat Sep 18 21:27:38 2021
NAMESPACE: harbor
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Please wait for several minutes for Harbor deployment to complete.
Then you should be able to visit the Harbor portal at https://192.168.10.61:30003
For more details, please visit https://github.com/goharbor/harbor

# リソース確認
$ kubectl get svc,po -n harbor
NAME                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                                     AGE
service/harbor                 NodePort    10.104.241.37    <none>        80:30002/TCP,443:30003/TCP,4443:30004/TCP   31s
service/harbor-chartmuseum     ClusterIP   10.108.128.15    <none>        80/TCP                                      32s
service/harbor-core            ClusterIP   10.104.189.102   <none>        80/TCP                                      32s
service/harbor-database        ClusterIP   10.109.171.244   <none>        5432/TCP                                    32s
service/harbor-jobservice      ClusterIP   10.105.25.179    <none>        80/TCP                                      31s
service/harbor-notary-server   ClusterIP   10.109.251.118   <none>        4443/TCP                                    32s
service/harbor-notary-signer   ClusterIP   10.105.221.7     <none>        7899/TCP                                    31s
service/harbor-portal          ClusterIP   10.107.233.75    <none>        80/TCP                                      31s
service/harbor-redis           ClusterIP   10.104.83.185    <none>        6379/TCP                                    31s
service/harbor-registry        ClusterIP   10.111.202.69    <none>        5000/TCP,8080/TCP                           31s
service/harbor-trivy           ClusterIP   10.108.112.117   <none>        8080/TCP                                    32s

NAME                                        READY   STATUS    RESTARTS   AGE
pod/harbor-chartmuseum-55f77977b9-42pd6     1/1     Running   0          31s
pod/harbor-core-598bd558d9-7bt5j            1/1     Running   0          31s
pod/harbor-database-0                       1/1     Running   0          31s
pod/harbor-jobservice-6b98cbdd6c-plgn8      0/1     Running   0          31s
pod/harbor-nginx-7dd96757cc-px78s           1/1     Running   0          31s
pod/harbor-notary-server-5c7d686c69-wkmk2   0/1     Running   0          31s
pod/harbor-notary-signer-7455598c86-68hf4   1/1     Running   0          31s
pod/harbor-portal-665c85cf78-n8wvf          1/1     Running   0          31s
pod/harbor-redis-0                          1/1     Running   0          31s
pod/harbor-registry-677cb9bd7d-slcl8        2/2     Running   0          31s
pod/harbor-trivy-0                          1/1     Running   0          31s

Web UI アクセス & リポジトリ作成

まずは Web UI にアクセスしてリポジトリ(プロジェクト)を作成します。
ログインに使う管理者(admin)のパスワードは values.yaml に設定されています。

values.yaml
・・・
# The initial password of Harbor admin. Change it from portal after launching Harbor
harborAdminPassword: "Harbor12345"
・・・

各サービスのポート情報は以下の values.yaml の通りです。

values.yaml
・・・
  nodePort:
    name: harbor
    ports:
      http:
        nodePort: 30002
      https:
        nodePort: 30003
      notary:
        nodePort: 30004
・・・

今回は https://192.168.10.61:30003/ にアクセスしてログインします。

自己署名証明書を利用しているので、警告文はスキップしてください

Project 画面で「NEW PROJECT」ボタンを押し、新しいプロジェクトを作成します。
今回は以下のパラメータで作成しました。

  • Project Name:sandbox
  • Access Level:Public にチェックはしない

プロジェクトの一覧に作成したプロジェクトが表示されています。

docker push/pull 準備

クライアント準備

docker push/pull するために、まずは docker をインストールします。今回は最新の docker をインストールするため、既存で入っているパッケージをアンインストールし、リポジトリ登録して docker を再インストールします。

# 古い docker をアンインストール
$ apt-get remove docker docker-engine docker.io containerd runc

# 必要なソフトウェアをインストール
$ apt-get update
$ apt-get install apt-transport-https 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=amd64 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
(2行分、ここまでコマンド)

$ cat /etc/apt/sources.list.d/docker.list
deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu   bionic stable

# リポジトリ情報を更新
$ apt-get update

# インストール対象のバージョンを確認
$ apt-cache madison docker-ce | grep 5.20
 docker-ce | 5:20.10.8~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:20.10.7~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:20.10.6~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:20.10.5~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:20.10.4~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:20.10.3~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:20.10.2~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:20.10.1~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:20.10.0~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages

# インストール対象が最新版なのでバージョン指定なしでインストール
$ apt-get install docker-ce docker-ce-cli containerd.io

# docker の起動確認
$ systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2021-09-18 17:08:49 UTC; 2h 15min ago
     Docs: https://docs.docker.com
 Main PID: 1106 (dockerd)
    Tasks: 8
   CGroup: /system.slice/docker.service
           mq1106 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

証明書準備(クライアント)

今回は自己署名証明書を利用しているため、クライアント・ノードそれぞれに証明書を配置します。まずは docker push するためにクライアントに証明書を配置していきます。Secret から証明書を取得します。

# 証明書配置ディレクトリ作成
$ mkdir -p /usr/share/ca-certificates/harbor

# 証明書ファイル出力
$ kubectl get secrets -n harbor harbor-nginx -o jsonpath='{.data.ca\.crt}' | base64 -d > /usr/share/ca-certificates/harbor/harbor.crt

# 証明書確認
$ cat /usr/share/ca-certificates/harbor/harbor.crt
-----BEGIN CERTIFICATE-----
・・・
-----END CERTIFICATE-----

# ルート証明書一覧更新
$ echo harbor/harbor.crt >> /etc/ca-certificates.conf

# ルート証明書再読み込み
$ update-ca-certificates
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.

# docker 再起動
$ systemctl restart docker

docker login コマンドでアクセスできるか確認しましょう。

$ docker login -u admin https://192.168.10.61:30003
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

証明書準備(ノード)

今度はノード側です。Pod 作成時にノードから Harbor に対して pull が行われるので、各ノードにルート証明書を配置しておきます。
前述のクライアントで行なった方法と一緒で、取得した証明書を各ノードに配置します。

$ ls -l /usr/share/ca-certificates/harbor/harbor.crt
$ echo harbor/harbor.crt >> /etc/ca-certificates.conf
$ update-ca-certificates

containerd を再起動します。

$ systemctl restart containerd

docker push

クライアント・ノードの準備ができたので、実際にイメージの登録とコンテナの作成を行なっていきます。まずはコンテナイメージを登録していきます。前述でも確認しましたが、再度 docker login で Harbor にログインしてみます。

$ docker login -u admin https://192.168.10.61:30003
Password:
・・・
Login Succeeded

登録するコンテナイメージを準備します。今回は busybox のコンテナイメージを Harbor に push します。

# busybox のコンテナイメージを pull
$ docker pull busybox:1.34.0
1.34.0: Pulling from library/busybox
35dacafcdad5: Pull complete
Digest: sha256:6502348b85ac820024584a459c0deeddf350db8ab3a6609f774483740511575a
Status: Downloaded newer image for busybox:1.34.0
docker.io/library/busybox:1.34.0

# リポジトリ用に名前・タグ付け
$ docker tag busybox:1.34.0 192.168.10.61:30003/sandbox/busybox:1.0
$ docker images
REPOSITORY                            TAG       IMAGE ID       CREATED      SIZE
busybox                               1.34.0    8336f9f1d094   4 days ago   1.24MB
192.168.10.61:30003/sandbox/busybox   1.0       8336f9f1d094   4 days ago   1.24MB

# Push !
$ docker push 192.168.10.61:30003/sandbox/busybox:1.0
The push refers to repository [192.168.10.61:30003/sandbox/busybox]
f6cb480bb44e: Pushed
1.0: digest: sha256:15f840677a5e245d9ea199eb9b026b1539208a5183621dced7b469f6aa678115 size: 527

Web UI で確認すると、push されたコンテナイメージを確認出来ます。

Pod デプロイ

登録したコンテナイメージを使って Pod をデプロイしていきます。
プロジェクト(リポジトリ)を Private で作成したので pull の際に認証情報が必要です。Secret で認証情報を作成します。今回は以下を参考に、docker login した際のトークン情報を利用します。

https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/

kubectl create secret generic の説明については以下の Secret のページを参照ください。
https://kubernetes.io/ja/docs/concepts/configuration/secret/

# kubectl create secret generic < secret名 >
# --from-file:ホームディレクトリ配下の .docker/config.json を指定
$ kubectl create secret generic harborcred \
--type=kubernetes.io/dockerconfigjson \
--from-file=.dockerconfigjson=/root/.docker/config.json \
-n default

secret/harborcred created

# 登録した Secret 確認
$ kubectl describe secret -n default harborcred
Name:         harborcred
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  kubernetes.io/dockerconfigjson

Data
====
.dockerconfigjson:  87 bytes

登録したコンテナイメージを使って Pod を作成します。マニフェストファイルは以下のとおりで、imagePullSecrets に登録した Secret を設定しています。

pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: default
spec:
  containers:
  - command:
    - sleep
    - "3600"
    image: 192.168.10.61:30003/sandbox/busybox:1.0
    name: busybox
  imagePullSecrets:
  - name: harborcred

準備が出来たのでデプロイして確認します。

$ kubectl apply -f pod.yaml
pod/busybox created

$ kubectl describe po busybox -n default
Name:         busybox
Namespace:    default
・・・
Containers:
  busybox:
・・・
    Image:         192.168.10.61:30003/sandbox/busybox:1.0
・・・
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  15s   default-scheduler  Successfully assigned default/busybox to nd01
  Normal  Pulling    16s   kubelet            Pulling image "192.168.10.61:30003/sandbox/busybox:1.0"
  Normal  Pulled     16s   kubelet            Successfully pulled image "192.168.10.61:30003/sandbox/busybox:1.0" in 570.776627ms
  Normal  Created    16s   kubelet            Created container busybox
  Normal  Started    16s   kubelet            Started container busybox

無事に登録したコンテナイメージで Pod を起動することが出来ました。

まとめ

helm での Harbor のデプロイはいかがでしたでしょうか。helm を使うと導入がはかどりますね。Harbor はコンテナイメージの管理だけでなく、WebUI からの操作や Helm Chart の管理、コンテナイメージのスキャンなどのセキュリティ機能もあり、機能としても豊富かと思います。プライベートリポジトリとして是非活用していきたいと思います。

補足

ノードの設定で、今回はルート証明書を登録しました。記事を書く際に確認したのですが、以下を containerd に設定することで自己署名証明書での Pod 起動ができることを確認しました。docker で言うところの /etc/docker/daemon.json にリポジトリを登録するに近い形かと思います。ご参考まで。

/etc/containerd/config.toml
[plugins]
  [plugins.cri.registry]
    [plugins.cri.registry.mirrors."192.168.10.61:30003"]
      endpoint = [
        "https://192.168.10.61:30003"
      ]
  [plugins.cri.registry.configs]
    [plugins.cri.registry.configs."192.168.10.61:30003".tls]
      insecure_skip_verify = true

Discussion

ログインするとコメントできます