Helmを使ってK3sにHarborをデプロイしてみた

どうも、Tです。

プライベートコンテナリポジトリとしてHarborをデプロイした備忘録です。

スポンサーリンク
アドセンス1

環境

Oracle Linux 10

# cat /etc/redhat-release 
Red Hat Enterprise Linux release 10.0 (CentOS Stream)
# uname -a
Linux k-harbor.k.local.lab 6.12.0-100.28.2.el10uek.x86_64 #1 SMP PREEMPT_DYNAMIC Mon May 19 19:28:24 PDT 2025 x86_64 GNU/Linux

K3s

# k3s --version
k3s version v1.32.6+k3s1 (eb603acd)
go version go1.23.10

Helm

# helm version
version.BuildInfo{Version:"v3.18.4", GitCommit:"d80839cf37d860c8aa9a0503fe463278f26cd5e2", GitTreeState:"clean", GoVersion:"go1.24.4"}

Harbor

# helm list --namespace harbor-system
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
harbor  harbor-system   1               2025-07-24 13:48:19.749107727 +0900 JST deployed        harbor-1.17.1   2.13.1 

やりたいこと

コンテナイメージを保存する必要があり、コンテナレジストリが必要になりました。

SaaSやクラウド型のコンテナレジストリも多数ありますが、無料枠で使おうとすると保存容量やデータ転送などに制限があるなど制約があり、検証用で好き勝手使えるようにオンプレにプライベートコンテナレジストリを作ることにしました。

オンプレで無料で使えるものコンテナレジストリとして、有名どころで下記2つがありました。

  • Docker Registry
  • Harbor

Docker Registryは、比較的お手軽に使えそうでしたが、コンテナイメージの管理画面がなくコマンド操作になるため、管理画面やその他多くの機能も備えているHarborを採用しました。

Harborについては下記にわかりやすく説明されています。

Harbor 詳細情報 | OSSサポートのOpenStandia™【NRI】
OSSの【Harbor】について、概要や動作確認、機能、特徴などを解説。OpenStandiaは、NRI(野村総合研究所)のオープンソースソフトウェアサポートサービスです。対象OSS120種類以上!

Harborのデプロイ方法は下記2通りあります。

  • Docker Composeを仕様してDockerにデプロイする
  • Helmを使用してKubernetesにデプロイする

Dockerへのデプロイはかなり面倒そうだったので、今回は後者のHelmを用いてKubernetesにデプロイしていきます。

Harbor – Harbor Installation and Configuration

なお、今回はとりあえず検証用として、コンテナレジストリを利用できれば良いためセキュリティやデータの永続化については考えず、一番簡単と思われる構成にしています。

事前準備

ホストOSの設定

ホストとなるOracle Linux 10を最小構成でインストールした後、下記の設定を行っています。

Harborを利用するために必須なわけではなく、私の検証環境の関係によるものです。

SELinux無効化

SELinuxを無効にし、OS再起動で反映します。

# sudo grubby --update-kernel ALL --args selinux=0

# reboot

SELinuxが無効であることを確認します。

# getenforce 
Disabled

Firewalld無効化

Firewalldの自動起動を無効にし、停止します。

 # systemctl disable --now firewalld

Firewalldが停止していることを確認します。

# systemctl status firewalld
○ firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; preset: enabled)
Active: inactive (dead)
Docs: man:firewalld(1)

Harborの要件について

Helmを用いたデプロイの要件としては、下記があります。今回は簡易的な構成のためKubernetes clusterとHelmバージョンを気にしておけば大丈夫だと思います。

Harbor – Deploying Harbor with High Availability via Helm

Prerequisites

  • Kubernetes cluster 1.10+
  • Helm 2.8.0+
  • High available ingress controller (Harbor does not manage the external endpoint)
  • High available PostgreSQL 9.6+ (Harbor does not handle the deployment of HA of database)
  • High available Redis (Harbor does not handle the deployment of HA of Redis)
  • PVC that can be shared across nodes or external object storage

また、Dockerにインストールする際の要件になりますが、Harborが多機能のためかハードウェア要件が高いです。今回は、ホストOSにRecommended程度のリソースを割り当てています。

Harbor – Harbor Installation Prerequisites

K3sインストール

HarborのためにKubernetesを準備するのは大変なので、今回は簡易に利用できるK3sを利用することにしました。

下記を参考にK3sをインストールします。

クイックスタートガイド | K3s
このガイドは、デフォルトオプションでクラスターを迅速に起動するのに役立ちます。インストールセクションでは、K3sのセットアップ方法について詳しく説明しています。

下記の環境変数を設定しSELinux関連のパッケージがインストールされないようにします。

# export INSTALL_K3S_SKIP_SELINUX_RPM=true

デフォルトでインストールを進めるとSELinux関連のパッケージをインストールするよう促されますが、実行するとエラーでインストールできませんでした。

[ERROR] Failed to apply container_runtime_exec_t to /usr/local/bin/k3s, please install:
dnf install -y container-selinux
dnf install -y https://rpm.rancher.io/k3s/stable/common/centos/9/noarch/

# dnf install -y https://rpm.rancher.io/k3s/stable/common/centos/9/noarch/
メタデータの期限切れの最終確認: 0:00:56 前の 2025年07月24日 12時13分32秒 に実施しました。
[MIRROR] : Status code: 404 for https://rpm.rancher.io/k3s/stable/common/centos/9/noarch/ (IP: 172.67.74.104) 
[MIRROR] : Status code: 404 for https://rpm.rancher.io/k3s/stable/common/centos/9/noarch/ (IP: 172.67.74.104) 
[MIRROR] : Status code: 404 for https://rpm.rancher.io/k3s/stable/common/centos/9/noarch/ (IP: 172.67.74.104) 
[MIRROR] : Status code: 404 for https://rpm.rancher.io/k3s/stable/common/centos/9/noarch/ (IP: 172.67.74.104) 
[FAILED] : Status code: 404 for https://rpm.rancher.io/k3s/stable/common/centos/9/noarch/ (IP: 172.67.74.104) 
Status code: 404 for https://rpm.rancher.io/k3s/stable/common/centos/9/noarch/ (IP: 172.67.74.104)

K3sをインストールします。

# curl -sfL https://get.k3s.io | K3S_KUBECONFIG_MODE="644" sh -s

「K3S_KUBECONFIG_MODE=”644″」を指定することで、rootユーザー以外でもkubectlコマンドを実行できるようになります。

上記オプションなしでインストール後、rootユーザー以外でkubectlコマンドを実行しようとすると下記のエラーがでます。

$ kubectl get nodes
WARN[0000] Unable to read /etc/rancher/k3s/k3s.yaml, please start server with --write-kubeconfig-mode or --write-kubeconfig-group to modify kube config permissions 
error: error loading config file "/etc/rancher/k3s/k3s.yaml": open /etc/rancher/k3s/k3s.yaml: permission denied

K3sが起動していることを確認します。(デフォルトで自動起動は有効になります)

]# systemctl status k3s
● k3s.service - Lightweight Kubernetes
     Loaded: loaded (/etc/systemd/system/k3s.service; enabled; preset: disabled)
     Active: active (running) since Thu 2025-07-24 12:15:09 JST; 3s ago
 Invocation: 9789d41ac8cd452694afa088cbac8419
       Docs: https://k3s.io
    Process: 1783 ExecStartPre=/bin/sh -xc ! /usr/bin/systemctl is-enabled --quiet nm-cloud-setup.service 2>/dev/null (>
    Process: 1785 ExecStartPre=/sbin/modprobe br_netfilter (code=exited, status=0/SUCCESS)
    Process: 1788 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SUCCESS)
   Main PID: 1791 (k3s-server)
      Tasks: 26
     Memory: 515.5M (peak: 515.5M)
        CPU: 9.942s
     CGroup: /system.slice/k3s.service
             ├─1791 "/usr/local/bin/k3s server"
             └─1813 "containerd "

下記のファイルパーミッションが644であることを確認します。

# ls -lha /etc/rancher/k3s/k3s.yaml
-rw-r--r-- 1 root root 2.9K 7月 24 12:15 /etc/rancher/k3s/k3s.yaml

ノードのステータスがReadyであることを確認します。なお、ここのNAMEは、OSのホスト名です。

# kubectl get nodes
NAME                   STATUS   ROLES                  AGE   VERSION
k-harbor.k.local.lab   Ready    control-plane,master   50s   v1.32.6+k3s1

Helmインストール

Helmは、Kubernetesのパッケージマネージャーです。

下記を参考にHelmをインストールします。

Installing Helm
Learn how to install and get running with Helm.

Helmをインストールするために必要なパッケージをインストールします。

# dnf install git openssl tar

Helmインストール作業に利用する作業用ディレクトリを作成して移動します。

# mkdir -p /root/work/helm
# cd /root/work/helm

Helmのインストールスクリプトをダウンロードし、スクリプトファイルがダウンロードできたことを確認します。

# curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
# ls -lh
合計 12K
-rw-r--r-- 1 root root 12K 7月 24 12:26 get_helm.sh

実行権限を付けて、インストールスクリプトを実行します。

# chmod 700 get_helm.sh
# ./get_helm.sh
Downloading https://get.helm.sh/helm-v3.18.4-linux-amd64.tar.gz
Verifying checksum... Done.
Preparing to install helm into /usr/local/bin
helm installed into /usr/local/bin/helm

Helmがインストールされたことを確認します。

# helm version
version.BuildInfo{Version:"v3.18.4", GitCommit:"d80839cf37d860c8aa9a0503fe463278f26cd5e2", GitTreeState:"clean", GoVersion:"go1.24.4"}

Harborデプロイ

下記を参考にHelmを用いて、Harborをデプロイします。

Harbor – Deploying Harbor with High Availability via Helm

helmのチャートリポジトリの登録

HelmはHemlチャートと呼ばれる定義ファイルとデプロイ用のパッケージングされたファイルに基づいてアプリケーションをデプロイします。HarborのHemlチャートが取得できるように、チャートリポジトリを登録します。

Harborのチャートリポジトリを登録し、リポジトリが表示されることを確認します。

# 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!⎈

Harborのチャート取得

HarborのHemlチャート作業に利用する作業ディレクトリを作成して移動します。

# mkdir -p /root/work/harbor
# cd /root/work/harbor

harborレジストリ/harborチャートを取得します。取得したディレクトリはharborになるので、ファイルが取得できていることを確認します。

# helm pull harbor/harbor --untar
# ls -lh
合計 0
drwxr-xr-x 3 root root 111 7月 24 12:36 harbor
# ls -lh harbor/
合計 248K
-rw-r--r-- 1 root root 637 7月 24 12:36 Chart.yaml
-rw-r--r-- 1 root root 12K 7月 24 12:36 LICENSE
-rw-r--r-- 1 root root 190K 7月 24 12:36 README.md
drwxr-xr-x 14 root root 220 7月 24 12:36 templates
-rw-r--r-- 1 root root 39K 7月 24 12:36 values.yaml

設定値修正

デプロイに必要となる設定値を修正します。

バックアップファイルを取得して編集していきます。

# cd harbor/
# cp -p values.yaml values.yaml.yyyymmdd
# vi values.yaml

下記の値を修正していきます。

---変更前
type: ingress
---変更後
type: nodePort
ingressでは、IPアドレス指定できずDNS名になるためIPアドレスで接続できるようにnodePortに変更します。

---変更前
commonName: ""
---変更後
commonName: "192.168.10.208"
ingress以外の場合に設定が必要です。WebのSSL証明書で利用されるCNになります。ホストOSのIPアドレスを指定します。

---変更前
externalURL: https://core.harbor.domain
---変更後
externalURL: https://192.168.10.208:30003
WebブラウザからアクセスするURLになります。30003はhttpsで接続する際のポートです。別の箇所で定義されているため3003を指定します。

diffで確認すると下記のようになります。

# diff -u values.yaml.20250724 values.yaml
--- values.yaml.20250724        2025-07-24 12:36:02.816063904 +0900
+++ values.yaml 2025-07-24 13:46:21.321986139 +0900
@@ -1,7 +1,7 @@
 expose:
   # Set 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 TLS or not.
     # Delete the "ssl-redirect" annotations in "expose.ingress.annotations" when TLS is disabled and "expose.type" is "ingress"
@@ -20,7 +20,7 @@
     auto:
       # The common name used to generate the certificate, it's necessary
       # when the type isn't "ingress"
-      commonName: ""
+      commonName: "192.168.10.208"
     secret:
       # The name of secret which contains keys named:
       # "tls.crt" - the certificate
@@ -109,7 +109,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.208:30003
 
 # The persistence is enabled by default and a default StorageClass
 # is needed in the k8s cluster to provision volumes dynamically.

Namespaceの追加

Harborデプロイ先となるK3sの任意の名前のNamespaceを作成し、作成されたことを確認します。

# kubectl create namespace harbor-system
namespace/harbor-system created

# kubectl get namespace
NAME              STATUS   AGE
default           Active   52m
harbor-system     Active   5s
kube-node-lease   Active   52m
kube-public       Active   52m
kube-system       Active   52m

環境変数(KUBECONFIG)設定

下記の環境変数を設定し、heml listコマンドで結果が表示できることを確認します。

# export KUBECONFIG=/etc/rancher/k3s/k3s.yaml

# helm list --all-namespaces
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                           APP VERSION
traefik         kube-system     1               2025-07-24 03:15:30.22891252 +0000 UTC  deployed        traefik-34.2.1+up34.2.0         v3.3.2     
traefik-crd     kube-system     1               2025-07-24 03:15:28.719047403 +0000 UTC deployed        traefik-crd-34.2.1+up34.2.0     v3.3.2

K3s環境では、helmから設定ファイルが認識できずhemlコマンドを実行すると下記のエラーが発生します。

Error: Kubernetes cluster unreachable: Get "http://localhost:8080/version": dial tcp [::1]:8080: connect: connection refused

今回は、インストール時のみ回避するためexportで環境変数を設定していますが、今後hemlコマンドを利用する場合は、.basrcあたりに下記の設定を入れておいてください。

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml

Harborのデプロイ

Harborをデプロイしてきます。

作業用ディレクトリに移動し、デプロイのコマンドを実行します。

# cd /root/work/harbor/
# helm install harbor --namespace harbor-system -f ./harbor/values.yaml harbor/harbor
NAME: harbor
LAST DEPLOYED: Thu Jul 24 13:48:19 2025
NAMESPACE: harbor-system
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.208:30003
For more details, please visit https://github.com/goharbor/harbor

少しわかりにくいのでコマンドの意味を記載します。

コマンド部分意味
helm installHelmチャートを使ってデプロイする
harborリリース名。helm list で表示される名前。
–namespace harbor-systemK3sで作成したNamespace。
-f ./harbor/values.yamlチャートの設定ファイルを指定。
harbor/harborharbborリポジトリのharborチャートを利用する指定。

デプロイ状況の確認

harborがデプロイされていることを確認します。

# helm list --namespace harbor-system
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
harbor  harbor-system   1               2025-07-24 13:48:19.749107727 +0900 JST deployed        harbor-1.17.1   2.13.1  

harborに関するpodなどのオブジェクトが多数デプロイされています。

# kubectl get all --namespace harbor-system
NAME                                     READY   STATUS    RESTARTS        AGE
pod/harbor-core-67bc47b787-wg9bc         1/1     Running   0               4m59s
pod/harbor-database-0                    1/1     Running   0               4m59s
pod/harbor-jobservice-6b87b6c7f5-dt29p   1/1     Running   2 (4m56s ago)   4m59s
pod/harbor-nginx-6c9f69989f-gzpnq        1/1     Running   0               4m59s
pod/harbor-portal-7ff4ddcbbb-xvlpf       1/1     Running   0               4m59s
pod/harbor-redis-0                       1/1     Running   0               4m59s
pod/harbor-registry-57d4479579-gl2jw     2/2     Running   0               4m59s
pod/harbor-trivy-0                       1/1     Running   0               4m59s

NAME                        TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
service/harbor              NodePort    10.43.50.158           80:30002/TCP,443:30003/TCP   4m59s
service/harbor-core         ClusterIP   10.43.26.120           80/TCP                       4m59s
service/harbor-database     ClusterIP   10.43.32.249           5432/TCP                     4m59s
service/harbor-jobservice   ClusterIP   10.43.45.253           80/TCP                       4m59s
service/harbor-portal       ClusterIP   10.43.51.111           80/TCP                       4m59s
service/harbor-redis        ClusterIP   10.43.14.36            6379/TCP                     4m59s
service/harbor-registry     ClusterIP   10.43.64.96            5000/TCP,8080/TCP            4m59s
service/harbor-trivy        ClusterIP   10.43.250.30           8080/TCP                     4m59s

NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/harbor-core         1/1     1            1           4m59s
deployment.apps/harbor-jobservice   1/1     1            1           4m59s
deployment.apps/harbor-nginx        1/1     1            1           4m59s
deployment.apps/harbor-portal       1/1     1            1           4m59s
deployment.apps/harbor-registry     1/1     1            1           4m59s

NAME                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/harbor-core-67bc47b787         1         1         1       4m59s
replicaset.apps/harbor-jobservice-6b87b6c7f5   1         1         1       4m59s
replicaset.apps/harbor-nginx-6c9f69989f        1         1         1       4m59s
replicaset.apps/harbor-portal-7ff4ddcbbb       1         1         1       4m59s
replicaset.apps/harbor-registry-57d4479579     1         1         1       4m59s

NAME                               READY   AGE
statefulset.apps/harbor-database   1/1     4m59s
statefulset.apps/harbor-redis      1/1     4m59s
statefulset.apps/harbor-trivy      1/1     4m59s

確認

externalURLに指定したURLでアクセスします。

https://192.168.10.208:30003

下記を入力しログインします。

  • Username:admin
  • Password:Harbor12345

 初期パスワードは、values.yamlの下記に記載されています。

# The initial password of Harbor admin. Change it from portal after launching Harbor
# or give an existing secret for it
# key in secret is given via (default to HARBOR_ADMIN_PASSWORD)
# existingSecretAdminPassword:
existingSecretAdminPasswordKey: HARBOR_ADMIN_PASSWORD
harborAdminPassword: "Harbor12345"

初期パスワードを変更しておきます。画面右上の「admin」->「Change Password」をクリックします。

新しいパスワードを入力し「OK」をクリックします。

参考

GitHub - goharbor/harbor: An open source trusted cloud native registry project that stores, signs, and scans content.
An open source trusted cloud native registry project that stores, signs, and scans content. - goharbor/harbor
Harbor – Deploying Harbor with High Availability via Helm
Helm を用いて Harbor を構築したい
mobさんのスクラップ
https://www.si1230.com/computer/software/container/kubernetes/kubernetes-conf/kubernetes-kubernetes%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%BC%E4%B8%8A%E3%81%ABhelm%E5%AF%BE%E5%BF%9C%E3%81%AEharbor%E3%82%92%E6%A7%8B%E7%AF%89/
helm で Harbor

まとめ

Helmを使うのは初めてでしたが、設定箇所を抑えておけば簡単にデプロイできました。

スポンサーリンク
アドセンス1
アドセンス1
ブログランキング・にほんブログ村へ

シェアする

フォローする