ラベル Docker の投稿を表示しています。 すべての投稿を表示
ラベル Docker の投稿を表示しています。 すべての投稿を表示
2024年10月5日土曜日

コンテナレジストリ「Harbor」バージョンアップ手順

Docker Hubのようにコンテナイメージを格納し、Dockerにてイメージをダウンロード(Pull)して利用できるようにするサービスをコンテナリポジトリと呼ぶ。

コンテナレジストリの「Harbor」は、OSSのコンテナレジストリであり、自宅検証環境にプライベートのコンテナレジストリを構築することができる。

↓コンテナレジストリ「Harbor」のインストール手順はこちら。

本記事では、コンテナレジストリ「Harbor」バージョンアップ手順を記載する。

環境

Harbor自体はDockerコンテナとして動作する。Harbor及びDockerが動作するOSとしてはAlmaLinuxを使用した。

  • OS : AlmaLinux release 8.10
  • Docker : 20.10.21
  • Docker Compose : v2.12.2
  • Harbor : v2.8.0→v2.11.1

今回の作業の簡単な概要図を以下に記載する。

バージョンアップ手順

1. アップグレードパスを確認

Harborはアップグレードパスが存在し、場合によっては段階的にバージョンアップ作業を行う必要がある。

アップグレードパスは残念ながらマニュアル等でまとまったページはないため、各バージョンアップ手順の記述を見て判断する必要がある。

今回の場合は、v2.8→v2.11のバージョンアップとなるので、まずはv2.11のマニュアルを確認する。

This guide covers upgrade and migration to v2.11.0. This guide only covers migration from v2.9.0 and later to the current version. If you are upgrading from an earlier version, refer to the migration guide for an earlier Harbor version.

上記の記載にあるように、v2.9.0以降であれば直接バージョンアップができるが、そうでない場合は、古いバージョンのマニュアルを見ること、と記載されている。

次にv2.9のマニュアルを確認する。

This guide covers upgrade and migration to v2.9.0. This guide only covers migration from v2.7.0 and later to the current version. If you are upgrading from an earlier version, refer to the migration guide for an earlier Harbor version.

こちらはv2.7.0以降であれば直接バージョンアップできる。今回はv2.8からのバージョンアップとなるので、アップグレードパスは「v2.8→v2.9→v.211」となることが確認できた。

2. インストーラの入手

Harborのインストーラは、オンラインインストーラとオフラインインストーラの2種類が用意されている。今回はオフラインインストーラを用いる。ダウンロードは以下URLからダウンロードすることができる。

今回の場合は、以下2つのファイルをダウンロードした。

  • harbor-offline-installer-v2.9.5.tgz
  • harbor-offline-installer-v2.11.1.tgz

3. Harbor停止

まず、起動中のHarborを停止する。

cd ~/harbor/
docker compose down

4. バックアップ

現在のバージョンのHarborの設定ファイルとデータベースのバックアップを行う。

cd ~
mkdir backup_2.8
mv harbor backup_2.8/harbor_2.8
cp -r /data/database ~/backup_2.8/

5. 新バージョンのファイルを展開

ダウンロードしたインストーラを展開し、インストーラに含まれるDockerイメージをロードする。

tar zxf harbor-offline-installer-v2.9.5.tgz
docker image load -i harbor/harbor.v2.9.5.tar.gz

6. 設定ファイルをマイグレーション

設定ファイル(harbor.yml)をマイグレーションする。

ls -l ~/backup_2.8/harbor_2.8/harbor.yml
cp ~/backup_2.8/harbor_2.8/harbor.yml ~/harbor
docker run -it --rm -v /:/hostfs goharbor/prepare:v2.9.5 migrate -i ~/harbor/harbor.yml

実際の実行結果は以下となる。

# docker run -it --rm -v /:/hostfs goharbor/prepare:v2.9.5 migrate -i ~/backup_2.8/harbor_2.8/harbor.yml
migrating to version 2.9.0
Written new values to /root/harbor/harbor.yml

7. 新バージョンインストール

以上で準備が整ったので、新バージョンのHarborをインストールおよび起動する。インストールはinstall.shを実行して実施する。

cd ~/harbor
./install.sh

8. ターゲットバージョンとなるまで、手順3~7を繰り返す

ターゲットバージョンとなるまで、手順3~7を繰り返す。バージョンが変わるため、フォルダパスやインストーラのファイル名の読み替えは必要となるが、手順に変更はない。

以下、参考情報として、v2.9→v2.11へのバージョンアップ手順を記載する。

cd ~/harbor/
docker compose down

cd ~
mkdir backup_2.9
mv harbor backup_2.9/harbor_2.9
cp -r /data/database ~/backup_2.9/

tar zxf harbor-offline-installer-v2.11.1.tgz
docker image load -i harbor/harbor.v2.11.1.tar.gz

ls -l ~/backup_2.9/harbor_2.9/harbor.yml
cp ~/backup_2.9/harbor_2.9/harbor.yml ~/harbor
docker run -it --rm -v /:/hostfs goharbor/prepare:v2.11.1 migrate -i ~/harbor/harbor.yml

cd ~/harbor
./install.sh

以上で、コンテナレジストリ「Harbor」バージョンアップ手順は完了となる。

2024年2月19日月曜日

Kubernetes構築手順① (cri-dockerdを使ってコントロールプレーンを構築)

今までminikubeを使ってKubernetes環境を手軽に構築をしてきたが、とうとう本家Kubernetesの構築を行うことにした。

Kubernetes構築は数回に分けて説明する。

本記事では、Kubernetesの管理機能であるコントールプレーンの構築手順を記載する。

なお、Kubernetesを利用する際は、CRI (Container Runtime Interface)と呼ばれるコンテナを操作するためのインタフェースを指定する必要がある。CRIにはcontainerd、CRI-O、Dockerなど選択できるが、今回はDocker用のCRIである「cri-dockerd」を利用する。

環境

以下に今回構築する各種ソフトウェアのバージョンを記載する。

  • ホストOS : AlmaLinux 8.6
  • Docker : 23.0.1
  • cri-dockerd: 0.3.1-dev
  • Kubernetes: v1.26.2

なお、私の環境ではインターネット接続時にプロキシ接続が必要となるため、プロキシ経由で接続するための設定も併せて行っている。

今回の構成の概要図を以下に記載する。

Dockerインストール

1. プロキシ設定 (必要な場合のみ)

私の環境ではプロキシ経由でなければインターネット接続ができないため、以下の通り環境変数を設定する。プロキシの環境変数について小文字と大文字の両方を設定している理由は、本環境変数はソフトウェアによっては小文字と大文字の区別をすることがあるため、念のため両方を設定している。

また、no_proxyの設定は、コントロールプレーンとなるホストのIPアドレスも指定している(今回であれば、192.168.11.51)。

export http_proxy=http://192.168.33.23:8080
export https_proxy=http://192.168.33.23:8080
export no_proxy=localhost,127.0.0.1,192.168.11.51,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
export HTTP_PROXY=http://192.168.33.23:8080
export HTTPS_PROXY=http://192.168.33.23:8080
export NO_PROXY=localhost,127.0.0.1,192.168.11.51,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16

2. Dockerインストール前の競合パッケージの削除

Kubernetesが利用するコンテナエンジンはDockerを用いることにする。まずは、Dockerをインストールする。

ただし、GUI環境をインストールしたAlmaLinuxの場合、以下の通りpodmanとcontainers-commonのパッケージが競合する旨のエラーでインストールに失敗する。

# dnf install docker-ce docker-ce-cli containerd.io -y
メタデータの期限切れの最終確認: 0:05:01 時間前の 2022年11月26日 12時46分04秒 に 実施しました。
エラー:
 問題 1: インストール済パッケージの問題 podman-2:4.0.2-6.module_el8.6.0+2878+e681bc44.x86_64
  - パッケージ podman-2:4.0.2-6.module_el8.6.0+2878+e681bc44.x86_64 には runc >= 1.0.0-57 が必要ですが、どのプロバイダーからもインストールできません
  - パッケージ podman-3:4.2.0-4.module_el8.7.0+3344+484dae7b.x86_64 には runc >= 1.0.0-57 が必要ですが、どのプロバイダーからもインストールできません

~(中略)~

 問題 2: インストール済パッケージの問題 containers-common-2:1-27.module_el8.6.0+2878+e681bc44.x86_64
  - パッケージ containers-common-2:1-27.module_el8.6.0+2878+e681bc44.x86_64 には runc が必要ですが、どのプロバイダーからもインストールできません
  - パッケージ containers-common-2:1-43.module_el8.7.0+3344+484dae7b.x86_64 には runc が必要ですが、どのプロバイダーからもインストールできません

~(中略)~

このような場合は、一度podmanとcontainers-commonのパッケージを削除したうえで、Dockerをインストールしよう。

# dnf remove podman containers-common

3. Dockerをインストール

Dockerのインストールは以下の通りコマンドを実行すればよい。

# dnf install yum-utils -y
# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# dnf install docker-ce docker-ce-cli containerd.io -y

4. Docker起動時の設定

プロキシ環境の場合は、外部からコンテナのダウンロードができるよう、systemctlの起動設定に環境変数の設定をしておくこと。

# sed -ie '/\[Service\]/a Environment="http_proxy=http://192.168.33.23:8080" "https_proxy=http://192.168.33.23:8080" "no_proxy=localhost,127.0.0.1,192.168.11.51,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"' /usr/lib/systemd/system/docker.service

また、Dockerのサービス起動時の設定ファイルであるdaemon.jsonを以下の通り作成する。Kubernetesを利用する場合は、以下2点を設定する必要がある。

  • cgroupdrivercgroupfssystemdに変更
  • insecure-registriesに必要に応じてプライベートのDockerコンテナレジストリを設定
# cat << EOF > /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ],
  "insecure-registries": [
    "192.168.11.54"
  ]
}
EOF

5. Dockerサービスを起動

最後に、Dockerのサービスを起動しておく。

# systemctl daemon-reload
# systemctl start docker
# systemctl enable docker

Kubernetesインストール

1. Kubernetesパッケージのリポジトリ設定

Kubernetesのリポジトリとして、以下の通りファイルを作成する。

# cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.28/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.28/rpm/repodata/repomd.xml.key
#exclude=kubelet kubeadm kubectl
EOF

2. Kubernetesパッケージインストール

Kubernetesのインストールに必要なパッケージとして、kubeletkubeadmkubectlをインストールする。また、関連して必要なパッケージであるiproute-tcも併せてインストールする。

パッケージ 説明
kubelet Kubernetesの各ノードにインストールされるエージェントとなり、Podの起動などを制御するサービス。
kubeadm Kubernetesの構築を行うためのツール。コントロールプレーンの構築や、
kubectl Kubernetesの管理を行うためのツール。
iproute-tc Linux Traffic Control utilityのパッケージ。
# dnf install kubelet kubeadm kubectl --disableexcludes=kubernetes -y
# dnf install iproute-tc -y

3. kubelet起動

インストールしたkubeletのサービスを起動させておく。

# systemctl start kubelet
# systemctl enable kubelet

4. swapの無効化

Kubernetesでは前提としてswapの無効化が必要となるため、無効化のコマンドを実行し、/etc/fstabにてswap領域をマウントしないよう設定する。

# swapoff -a
# sed -ie 's|\(^/dev/.* swap .*\)|#\1|' /etc/fstab

cri-dockerdインストール

1. 前提パッケージインストール

cri-dockerdは、GitHubに公開されているソースを用いてビルドしインストールする。そのため、gitwgetのパッケージをインストールする。

# dnf install git wget -y

2. cri-dockrdをビルド及び配置

cri-dockerdはgo言語を用いているため、goコマンドをインストールする。

goコマンドをインストールするためのツールが用意されているので、ダウンロードしてインストールする。rootでコマンドを実行した場合は、/root/.go/bin/goにインストールされ、~/.bash_profileにもパスが追記される。

# mkdir /tmp/cri-dockerd
# cd /tmp/cri-dockerd
# wget https://storage.googleapis.com/golang/getgo/installer_linux
# chmod +x ./installer_linux
# ./installer_linux
# source ~/.bash_profile

次に、cri-dockerdのソースをgit cloneしダウンロードする。

# git clone https://github.com/Mirantis/cri-dockerd.git

ダウンロードしたソースをビルドし、systemdのディレクトリに配置する。

# cd cri-dockerd
# mkdir -p bin
# go build -o bin/cri-dockerd
# install -o root -g root -m 0755 bin/cri-dockerd /usr/local/bin/cri-dockerd
# cp -a packaging/systemd/* /etc/systemd/system
# sed -i -e 's,/usr/bin/cri-dockerd,/usr/local/bin/cri-dockerd,' /etc/systemd/system/cri-docker.service

3. cri-dockrdを起動

cri-dockerdをサービスとして起動する。

# systemctl daemon-reload
# systemctl enable cri-docker.service
# systemctl enable --now cri-docker.socket

kubeadmコマンドを用いてKubernetesクラスター作成

1. kubeadmコマンド実行

kubeadmコマンドを用いて、Kubernetesクラスターの作成を行う。クラスターの作成はkubeadm initコマンドにて実施する。「Your Kubernetes control-plane has initialized successfully!」が表示されれば成功となる。

オプションの説明を以下に記載する。

オプション 説明
--pod-network-cidr=10.244.0.0/16 ネットワークアドオンとしてflannelを追加する際に必要となる設定となる。Pod用のクラスターネットワークのネットワークアドレスを指定する。
--cri-socket=unix:///var/run/cri-dockerd.sock CRIとしてcri-dockerdを使うことを明示的に指定するために指定する。指定しない場合、containerdとcri-dockerdの2つがインストールされていることにより、「Found multiple CRI endpoints on the host」のエラーにてクラスターの作成に失敗するので注意しよう。
# kubeadm init --pod-network-cidr=10.244.0.0/16 --cri-socket=unix:///var/run/cri-dockerd.sock
[init] Using Kubernetes version: v1.26.2
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'

~(中略)~

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.11.51:6443 --token bexxee.xx866gxx91sxxa69 \
        --discovery-token-ca-cert-hash sha256:06d8e3077c71a3f7af2xx8d6b389d43673xx9a8axxa5d003ed8dccb356a42f80

2. Kubernetesクラスター状態確認

Kubernetesの管理はkubectlコマンドを使って実施するが、そのままでは使用できないので、環境変数で設定ファイルのパスを指定しておく。

# export KUBECONFIG=/etc/kubernetes/admin.conf

それでは、kubectlコマンドを使って、PodとNodeの状態を確認してみよう。以下の通り、各種コントロールプレーン用のPodと1台のNodeが表示される。

# kubectl get pod -A
NAMESPACE     NAME                                READY   STATUS    RESTARTS   AGE
kube-system   coredns-787d4945fb-cf2sf            0/1     Pending   0          45s
kube-system   coredns-787d4945fb-wkp86            0/1     Pending   0          45s
kube-system   etcd-t1051kube                      1/1     Running   0          59s
kube-system   kube-apiserver-t1051kube            1/1     Running   0          60s
kube-system   kube-controller-manager-t1051kube   1/1     Running   0          60s
kube-system   kube-proxy-lscpc                    1/1     Running   0          46s
kube-system   kube-scheduler-t1051kube            1/1     Running   0          60s

# kubectl get node
NAME        STATUS     ROLES           AGE   VERSION
t1051kube   NotReady   control-plane   83s   v1.26.2

上記を見ると、corednsがPendingのステータスとなっており、NodeのステータスもNotReadyとなっている。これはPod用のネットワークアドオンがインストールされていないために発生しており、後続の手順にてflannelをインストールするとステータスがRunningになるため、現時点では気にしなくて問題ない

ネットワークアドオンインストール (flannelインストール)

1. flannelインストール

Kubernetesのネットワークアドオンはいくつか選択肢があるようだが、今回はflannnelを利用する。flannelはインストール用のマニフェストファイルが公開されており、Kubernetes環境に適用するだけでインストールできる。

# cd ~
# curl -LO https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

# kubectl apply -f kube-flannel.yml
namespace/kube-flannel created
serviceaccount/flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created

2. インストール後のPodとNodeの状態確認

インストール後、1分ほど待ってから再度PodとNodeの状態を確認してみよう。PendingステータスだったcorednsがRunningになり、NodeのステータスもReadyになっているはずだ。

# kubectl get pod -A
NAMESPACE      NAME                                READY   STATUS    RESTARTS   AGE
kube-flannel   kube-flannel-ds-8s4cq               1/1     Running   0          41s
kube-system    coredns-787d4945fb-cf2sf            1/1     Running   0          2m43s
kube-system    coredns-787d4945fb-wkp86            1/1     Running   0          2m43s
kube-system    etcd-t1051kube                      1/1     Running   0          2m57s
kube-system    kube-apiserver-t1051kube            1/1     Running   0          2m58s
kube-system    kube-controller-manager-t1051kube   1/1     Running   0          2m58s
kube-system    kube-proxy-lscpc                    1/1     Running   0          2m44s
kube-system    kube-scheduler-t1051kube            1/1     Running   0          2m58s

# kubectl get node
NAME        STATUS   ROLES           AGE     VERSION
t1051kube   Ready    control-plane   3m17s   v1.26.2

以上で、Kubernetesの管理機能であるコントールプレーンの構築手順は完了となる。とはいえ、これだけでは実際にコンテナを起動させることもできないため、次回以降でワーカーノードを追加していく。

更新履歴

  • 2023/3/11 新規作成
  • 2024/2/19 リポジトリのURLを最新情報に更新

2023年8月12日土曜日

TerraformをAlmaLinuxにインストールして簡単な動作確認をしてみた

Terraformは、HashiCorp社にて開発された各種プラットフォームのITインフラの設定をIaC (Infrastructure as code)にて設定可能とするOSSツールとなる。

今回は、TerraformをAlmaLinuxにインストールし、簡単な動作確認を行う手順を記載する。

環境

環境は以下の通り。

  • OS : AlmaLinux 9.2
  • Terraform : v1.5.2

Terraformインストール手順

1. HashiCorpのレポジトリ追加

TerraformはHashicorpのリポジトリで公開されている。yum-config-managerコマンドを使って、以下の通りリポジトリの追加を行う。

# dnf install yum-utils -y
# yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo

2. Terraformインストール

dnfを用いてTerraformをインストールする。gitperlの各種ライブラリが依存関係パッケージとして、大量にインストールされる。

# dnf install terraform
メタデータの期限切れの最終確認: 0:00:16 前の 2023年07月07日 21時12分38秒 に実施しました。
依存関係が解決しました。
====================================================================================================================================================
 パッケージ                                 アーキテクチャー           バージョン                               リポジトリー                  サイズ
====================================================================================================================================================
インストール:
 terraform                                  x86_64                     1.5.2-1                                  hashicorp                      21 M
依存関係のインストール:
 emacs-filesystem                           noarch                     1:27.2-8.el9_2.1                         appstream                     7.9 k
 git                                        x86_64                     2.39.3-1.el9_2                           appstream                      61 k
 git-core                                   x86_64                     2.39.3-1.el9_2                           appstream                     4.2 M
 git-core-doc                               noarch                     2.39.3-1.el9_2                           appstream                     2.6 M
 perl-AutoLoader                            noarch                     5.74-480.el9                             appstream                      21 k
 perl-B                                     x86_64                     1.80-480.el9                             appstream                     179 k
 perl-Carp                                  noarch                     1.50-460.el9                             appstream                      29 k
 perl-Class-Struct                          noarch                     0.66-480.el9                             appstream                      22 k

~(中略)~

 perl-subs                                  noarch                     1.03-480.el9                             appstream                      12 k
 perl-vars                                  noarch                     1.05-480.el9                             appstream                      13 k
弱い依存関係のインストール:
 perl-IO-Socket-SSL                         noarch                     2.073-1.el9                              appstream                     216 k
 perl-Mozilla-CA                            noarch                     20200520-6.el9                           appstream                      12 k
 perl-NDBM_File                             x86_64                     1.15-480.el9                             appstream                      22 k

トランザクションの概要
====================================================================================================================================================
インストール  68 パッケージ

ダウンロードサイズの合計: 34 M
インストール後のサイズ: 123 M
これでよろしいですか? [y/N]: y

~(以下略)~

インストール後、Terraformのバージョンを確認しておこう。

# terraform -v
Terraform v1.5.2
on linux_amd64
+ provider registry.terraform.io/kreuzwerker/docker v3.0.2

3. terraformコマンドのTab補完を使えるようにする

Terraformを使用する際は、その名の通りterraformコマンドを使用する。その際にTab補完を使えるよう、以下の通りコマンドを実行する。

# touch ~/.bashrc
# terraform -install-autocomplete
# source ~/.bashrc

実行後の~/.bashrcは以下の通り。最終行にTab補完用のコマンドが実行されるようになっている。

~/.bashrc

# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]
then
    PATH="$HOME/.local/bin:$HOME/bin:$PATH"
fi
export PATH

# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

complete -C /usr/bin/terraform terraform   # <- ★追加される

これによって、例えばterraform a[TAB]とキーを入力すれば、terraform applyのコマンドが補完されるようになる。

# terraform apply   <- ★Tabで補完されるようになる

Terraform動作確認 (Docekrコンテナ作成)

ここからは、公式サイトで公開されている以下のチュートリアル通りに確認作業を進める。

前提として、事前にTerraformを導入したOSにDockerをインストールすること。Dockerのインストール手順は以下を参照いただきたい。

1. 作業用ディレクトリ作成

Terraformでは、作業用ディレクトリを作成し、そこに*.tfという拡張子を持つファイルにてTerraformのコードを記載する。Terraformコマンドはtfファイルのコードを解釈し、必要な一時ファイル等をディレクトリ内に作成し、各プラットフォームに対して操作を行う。

今回は以下の通りディレクトリを作成する。

# mkdir learn-terraform-docker-container
# cd learn-terraform-docker-container

2. tfファイルを作成

作成したディレクトリ内にmain.tfというファイルを作成し、以下の通り記述する。

main.tf

terraform {
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"
      version = "~> 3.0.1"
    }
  }
}

provider "docker" {}

resource "docker_image" "nginx" {
  name         = "nginx"
  keep_locally = false
}

resource "docker_container" "nginx" {
  image = docker_image.nginx.image_id
  name  = "tutorial"

  ports {
    internal = 80
    external = 8000
  }
}

3. Terraform初期化 (terraform init)

Terraformを初期化するため、terraform initコマンドを実行する。このコマンドを実行すると、プロバイダと呼ばれるプラットフォームとのインタフェースとなるファイルが.terraformディレクトリにダウンロードされる。使用するプロバイダによってはかなり容量が大きいため注意しよう(例えばAWSのプロバイダであれば400MB程度)。

# terraform init

Initializing the backend...

Initializing provider plugins...
- Finding kreuzwerker/docker versions matching "~> 3.0.1"...
- Installing kreuzwerker/docker v3.0.2...
- Installed kreuzwerker/docker v3.0.2 (self-signed, key ID BD080C4571C6104C)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

なお、Terraformで使用可能なプロバイダは、以下URLから確認できる。

4. Terraform実行前確認 (terraform plan)

実行前に実行内容を確認するため、terraform planコマンドを実行する。

# terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # docker_container.nginx will be created
  + resource "docker_container" "nginx" {
      + attach                                      = false
      + bridge                                      = (known after apply)
      + command                                     = (known after apply)
      + container_logs                              = (known after apply)
      + container_read_refresh_timeout_milliseconds = 15000
      + entrypoint                                  = (known after apply)
      + env                                         = (known after apply)
      + exit_code                                   = (known after apply)
      + hostname                                    = (known after apply)
      + id                                          = (known after apply)
      + image                                       = (known after apply)
      + init                                        = (known after apply)
      + ipc_mode                                    = (known after apply)
      + log_driver                                  = (known after apply)
      + logs                                        = false
      + must_run                                    = true
      + name                                        = "tutorial"
      + network_data                                = (known after apply)
      + read_only                                   = false
      + remove_volumes                              = true
      + restart                                     = "no"
      + rm                                          = false
      + runtime                                     = (known after apply)
      + security_opts                               = (known after apply)
      + shm_size                                    = (known after apply)
      + start                                       = true
      + stdin_open                                  = false
      + stop_signal                                 = (known after apply)
      + stop_timeout                                = (known after apply)
      + tty                                         = false
      + wait                                        = false
      + wait_timeout                                = 60

      + ports {
          + external = 8000
          + internal = 80
          + ip       = "0.0.0.0"
          + protocol = "tcp"
        }
    }

  # docker_image.nginx will be created
  + resource "docker_image" "nginx" {
      + id           = (known after apply)
      + image_id     = (known after apply)
      + keep_locally = false
      + name         = "nginx"
      + repo_digest  = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

5. Terraform実行 (terraform apply)

Terraformの処理をするため、terraform applyコマンドを実行する。

# terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # docker_container.nginx will be created
  + resource "docker_container" "nginx" {
      + attach                                      = false
      + bridge                                      = (known after apply)
      + command                                     = (known after apply)
      + container_logs                              = (known after apply)
      + container_read_refresh_timeout_milliseconds = 15000
      + entrypoint                                  = (known after apply)
      + env                                         = (known after apply)
      + exit_code                                   = (known after apply)
      + hostname                                    = (known after apply)
      + id                                          = (known after apply)
      + image                                       = (known after apply)
      + init                                        = (known after apply)
      + ipc_mode                                    = (known after apply)
      + log_driver                                  = (known after apply)
      + logs                                        = false
      + must_run                                    = true
      + name                                        = "tutorial"
      + network_data                                = (known after apply)
      + read_only                                   = false
      + remove_volumes                              = true
      + restart                                     = "no"
      + rm                                          = false
      + runtime                                     = (known after apply)
      + security_opts                               = (known after apply)
      + shm_size                                    = (known after apply)
      + start                                       = true
      + stdin_open                                  = false
      + stop_signal                                 = (known after apply)
      + stop_timeout                                = (known after apply)
      + tty                                         = false
      + wait                                        = false
      + wait_timeout                                = 60

      + ports {
          + external = 8000
          + internal = 80
          + ip       = "0.0.0.0"
          + protocol = "tcp"
        }
    }

  # docker_image.nginx will be created
  + resource "docker_image" "nginx" {
      + id           = (known after apply)
      + image_id     = (known after apply)
      + keep_locally = false
      + name         = "nginx"
      + repo_digest  = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes   <- ★yesを入力

docker_image.nginx: Creating...
docker_image.nginx: Creation complete after 9s [id=sha256:021283c8eb95be02b23db0de7f609d603553c6714785e7a673c6594a624ffbdanginx]
docker_container.nginx: Creating...
docker_container.nginx: Creation complete after 1s [id=c70291e91ade2fef0b1051a92a7a7e657d9b32c8bf63cafb7e5a3a4b7449bca2]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

6. 実行後確認

実行後にDockerコンテナとコンテナイメージの状況を確認すると、NGINXのコンテナイメージがダウンロードされ、コンテナとして起動していることがわかる。

# docker ps
CONTAINER ID   IMAGE          COMMAND                   CREATED          STATUS          PORTS                  NAMES
c70291e91ade   021283c8eb95   "/docker-entrypoint.…"   27 seconds ago   Up 26 seconds   0.0.0.0:8000->80/tcp   tutorial

# docker images
REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
nginx        latest    021283c8eb95   4 days ago   187MB

NGINXコンテナは8000番ポートで接続できる。実際に接続すると、NGINXのウェルカムページが表示された。

7. Dockerコンテナ削除 (terraform destroy)

Terraformで作成したDockerコンテナを削除するため、terraform destroyコマンドを実行する。

# terraform destroy
docker_image.nginx: Refreshing state... [id=sha256:021283c8eb95be02b23db0de7f609d603553c6714785e7a673c6594a624ffbdanginx]
docker_container.nginx: Refreshing state... [id=c70291e91ade2fef0b1051a92a7a7e657d9b32c8bf63cafb7e5a3a4b7449bca2]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # docker_container.nginx will be destroyed
  - resource "docker_container" "nginx" {
      - attach                                      = false -> null
      - command                                     = [
          - "nginx",
          - "-g",
          - "daemon off;",
        ] -> null
      - container_read_refresh_timeout_milliseconds = 15000 -> null
      - cpu_shares                                  = 0 -> null
      - dns                                         = [] -> null
      - dns_opts                                    = [] -> null
      - dns_search                                  = [] -> null
      - entrypoint                                  = [
          - "/docker-entrypoint.sh",
        ] -> null
      - env                                         = [] -> null
      - group_add                                   = [] -> null
      - hostname                                    = "c70291e91ade" -> null
      - id                                          = "c70291e91ade2fef0b1051a92a7a7e657d9b32c8bf63cafb7e5a3a4b7449bca2" -> null
      - image                                       = "sha256:021283c8eb95be02b23db0de7f609d603553c6714785e7a673c6594a624ffbda" -> null
      - init                                        = false -> null
      - ipc_mode                                    = "private" -> null
      - log_driver                                  = "json-file" -> null
      - log_opts                                    = {} -> null
      - logs                                        = false -> null
      - max_retry_count                             = 0 -> null
      - memory                                      = 0 -> null
      - memory_swap                                 = 0 -> null
      - must_run                                    = true -> null
      - name                                        = "tutorial" -> null
      - network_data                                = [
          - {
              - gateway                   = "172.17.0.1"
              - global_ipv6_address       = ""
              - global_ipv6_prefix_length = 0
              - ip_address                = "172.17.0.2"
              - ip_prefix_length          = 16
              - ipv6_gateway              = ""
              - mac_address               = "02:42:ac:11:00:02"
              - network_name              = "bridge"
            },
        ] -> null
      - network_mode                                = "default" -> null
      - privileged                                  = false -> null
      - publish_all_ports                           = false -> null
      - read_only                                   = false -> null
      - remove_volumes                              = true -> null
      - restart                                     = "no" -> null
      - rm                                          = false -> null
      - runtime                                     = "runc" -> null
      - security_opts                               = [] -> null
      - shm_size                                    = 64 -> null
      - start                                       = true -> null
      - stdin_open                                  = false -> null
      - stop_signal                                 = "SIGQUIT" -> null
      - stop_timeout                                = 0 -> null
      - storage_opts                                = {} -> null
      - sysctls                                     = {} -> null
      - tmpfs                                       = {} -> null
      - tty                                         = false -> null
      - wait                                        = false -> null
      - wait_timeout                                = 60 -> null

      - ports {
          - external = 8000 -> null
          - internal = 80 -> null
          - ip       = "0.0.0.0" -> null
          - protocol = "tcp" -> null
        }
    }

  # docker_image.nginx will be destroyed
  - resource "docker_image" "nginx" {
      - id           = "sha256:021283c8eb95be02b23db0de7f609d603553c6714785e7a673c6594a624ffbdanginx" -> null
      - image_id     = "sha256:021283c8eb95be02b23db0de7f609d603553c6714785e7a673c6594a624ffbda" -> null
      - keep_locally = false -> null
      - name         = "nginx" -> null
      - repo_digest  = "nginx@sha256:08bc36ad52474e528cc1ea3426b5e3f4bad8a130318e3140d6cfe29c8892c7ef" -> null
    }

Plan: 0 to add, 0 to change, 2 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes   <- ★yesを入力

docker_container.nginx: Destroying... [id=c70291e91ade2fef0b1051a92a7a7e657d9b32c8bf63cafb7e5a3a4b7449bca2]
docker_container.nginx: Destruction complete after 0s
docker_image.nginx: Destroying... [id=sha256:021283c8eb95be02b23db0de7f609d603553c6714785e7a673c6594a624ffbdanginx]
docker_image.nginx: Destruction complete after 0s

Destroy complete! Resources: 2 destroyed.

削除後にDockerコンテナとコンテナイメージを確認すると、いずれも削除されていることが確認できる。

# docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

# docker images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

以上で、TerraformをAlmaLinuxにインストールし、簡単な動作確認を行う手順は完了となる。

参考

2023年5月6日土曜日

OSSのコンテナレジストリ「Harbor」を自己署名証明書でHTTPS通信させる

以前、OSSのコンテナレジストリ「Harbor」を構築する手順を記載した。

上記手順では、手順簡略化のためにHarborとDocker間をHTTPにて通信するよう構成したが、本来HarborもDockerもHTTPSによるSSL通信を前提としている。

そこで今回は、Harborに自己署名証明書を登録し、HarborとDocker間をHTTPSにて通信できるよう構成してみた。

環境

Harbor自体はDockerコンテナとして動作する。Harbor及びDockerが動作するOSとしてはAlmaLinuxを使用した。

  • OS : AlmaLinux release 8.6
  • Docker : 23.0.5
  • Docker Compose : v2.17.3
  • Harbor : v2.8.0

Harborをインストールするサーバのホスト名とIPアドレスは以下となり、DNSで名前解決できる状態としてある。

  • ホスト名 : t1050harb
  • IPアドレス : 192.168.11.50

自己署名証明書作成

自己署名証明書のSSLサーバ証明書の作成手順は、以下記事を参照すること。

本記事では、手順の概要のみ記載する。

1. 秘密鍵の作成

秘密鍵を作成するディレクトリは任意の場所で問題ないが、不特定多数が見れないディレクトリが望ましい。

今回は/etc/pki/tls/misc/に作成することとする。秘密鍵はopensslコマンドを使って以下の通り作成する。

# cd /etc/pki/tls/misc/
# openssl genrsa 2048 > server.key

2. CSRを作成

作成した秘密鍵からCSRを作成する。

# openssl req -new -key server.key > server.csr

オレオレ認証局として構築済みのサーバに、先ほど作成したserver.csrをコピーし、/etc/pki/tls/misc/newreq.pemというファイル名で配置する。

3. SAN情報を作成

近年のサーバ証明書は、Common Nameに記載された情報ではなく、SAN(Subject Alternative Name; サブジェクト代替名)と呼ばれる情報に記載されたFQDNやIPアドレスの情報と、接続先のURLが一致することを確認する。

今回は、SANの情報として、Harborのホスト名、FQDN、IPアドレスを登録するようにした。

# cd /etc/pki/tls/misc/
# cat << EOF > san.txt
subjectAltName = DNS:t1050harb, DNS:t1050harb..example.com, IP:192.168.11.50
EOF

4. オレオレ認証局にて署名

CSRへの署名はCAスクリプトを用いて実施する。Red Hat 8以降のopensslにはCAスクリプトが含まれていないため、以前のバージョンのRPMなどから入手すること。

# ./CA -sign

作成された証明書はnewcert.pemという名前で保存されるので、ファイル名を変えておこう。

# ls -l newcert.pem
-rw-r--r-- 1 root root 4199  4月 29 13:08 newcert.pem
cp newcert.pem server_t1050harb.crt

5. 秘密鍵とサーバ証明書を配置

作成した秘密鍵とサーバ証明書は、それぞれ以下ディレクトリに配置する。

証明書 ファイル名 ディレクトリ
サーバ証明書 server_t1050harb.crt /etc/pki/tls/certs/
秘密鍵 server_t1050harb.key /etc/pki/tls/private/

Harborインストール

Harborのインストール手順も大きくは以前の記事の手順と変わらない。

インストール時に使用する設定ファイルであるharbor.ymlのみ差異があるため、その個所を抜粋して記載する。

1. harbor.ymlの修正

HTTPSで通信させる場合は、harbor.ymlの修正箇所は以下3か所のみとなる。

  • hostname
  • certificate
  • private_key

harbor.yml

# Configuration file of Harbor

# The IP address or hostname to access admin UI and registry service.
# DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
hostname: t1050harb.example.com ←★ホスト名を設定する。DNSなどで名前解決できる場合はFQDN設定が望ましい

# http related config
http:
  # port for http, default is 80. If https enabled, this port will redirect to https port
  port: 80

# https related config
https:
  # https port for harbor, default is 443
  port: 443
  # The path of cert and key files for nginx
  certificate: /etc/pki/tls/certs/server_t1050harb.crt ←★サーバ証明書のパスを指定
  private_key: /etc/pki/tls/private/server_t1050harb.key ←★秘密鍵のパスを指定

~(以下略)~

4. ログイン確認

harbor.yml修正後インストールを行い、HarborのGUIに以下デフォルトユーザー・パスワードでアクセスしてみよう。

  • ユーザー名 : admin
  • パスワード : Harbor12345

ブラウザで証明書情報を確認すると、作成した自己署名証明書でHTTPS通信されていることが確認できる。オレオレ認証局のCA証明書を「信頼されたルート証明機関」の証明書として登録しておけば、ブラウザの証明書エラーも表示されることなくアクセスできる。

DockerからHarborへ接続

次にDockerからHTTPSで接続するための設定を行う。結論から言うと、単純に何もしないと以下の通りdocker loginした際にx509: certificate signed by unknown authorityのエラーで失敗する。

# docker login 192.168.11.50
Username: admin
Password:
Error response from daemon: Get "https://192.168.11.50/v2/": x509: certificate signed by unknown authority

1. オレオレ人書局のCA証明書を「信頼されたルート証明機関」の証明書として配置

エラーを解消するために、オレオレ人書局のCA証明書を信頼される証明書として配置する。Dockerの場合はOSの証明書設定とは別に、以下ルールに沿った配置が必要となる。

  • ディレクトリは/etc/docker/certs.d/[FQDN or IPアドレス]で作成する
  • CA証明書のファイルはca.crtというファイル名にする

今回は、DockerからIPアドレスで接続するため、192.168.11.50でフォルダを作成し、CA証明書を配置する。

# mkdir -p /etc/docker/certs.d/192.168.11.50
# cp /tmp/ca.crt /etc/docker/certs.d/192.168.11.50/ca.crt

2. Dcokerから接続確認

Doockerからの接続確認は、docker loginコマンドで行う。ユーザ名・パスワードは、HarborのGUIログイン時に使用するものと同じとなる。

  • ユーザー名 : admin
  • パスワード : Harbor12345

以下のようにLogin Succeededと表示されれば成功となる。

# docker login 192.168.11.50
Username: admin
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

もし、以下のようにService Unavailableのエラーが表示される場合は、何らかの理由でコンテナレジストリへの接続に失敗している。

# docker login 192.168.11.50
Username: admin
Password:
Error response from daemon: Get "https://192.168.11.50/v2/": Get "https://t1050harb..example.com/service/token?account=admin&client_id=docker&offline_token=true&service=harbor-registry": Service Unavailable

Service Unavailableのエラーの場合は、そもそも接続に失敗している可能性がある。DNSの名前解決(DNSを使えない場合はhostsにレコードを登録する)や、プロキシ除外設定(IPアドレスだけでなくFQDNも除外する)などの設定に問題がないか確認してみよう。

最後に、docker logoutを実行し、認証情報の削除を行う。

# docker logout 192.168.11.50
Removing login credentials for 192.168.11.50

以上で、Harborに自己署名証明書を登録し、HarborとDocker間をHTTPSにて通信できるよう構成する手順は完了となる。

2023年3月25日土曜日

Kubernetes構築手順③ (マニフェストファイルを使ってDockerコンテナをデプロイ)

前回、前々回において、Kubernetesのコントロールプレーンの構築とワーカーノードを追加する手順を記載した。

本記事では、構築したKubernetes環境にマニフェストファイルを使ってDockerコンテナをデプロイする手順を記載する。

環境

以下に今回構築する各種ソフトウェアのバージョンを記載する。

  • ホストOS : AlmaLinux 8.6
  • Docker : 23.0.1
  • cri-dockerd: 0.3.1-dev
  • Kubernetes: v1.26.2

今回の構成の概要図を以下に記載する。

マニフェストファイルの準備

マニフェストファイルは、Pod用とサービスリソース用の2種類を作成する。マニフェストファイルの記載方法の説明は、過去minikubeで検証した際に説明をしているので、参考にしていただきたい。

1. Pod用マニフェストファイル

検証用のPodのコンテナイメージは、minikubeでも確認用途で使用していたkicbase/echo-serverを使用する。コントロールプレーン含め、3台のノードにPodが配置されることを確認するため、replicas: 3を設定した。

deployment-hello.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-k8s-deployment
  labels:
    app: hello-k8s-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-k8s
  template:
    metadata:
      labels:
        app: hello-k8s
    spec:
      containers:
      - name: hello-k8s
        image: kicbase/echo-server:1.0
        imagePullPolicy: Always

2. サービスリソース用マニフェストファイル

サービスリソースのタイプはNodePortを選択し、各ノードのIPアドレスにアクセスした際に、Podに接続を振り分けるよう設定する。

service-hello.yml

apiVersion: v1
kind: Service
metadata:
  name: hello-k8s-service
  labels:
    app: hello-k8s-service
spec:
  selector:
    app: hello-k8s
  ports:
    - port: 8080
  type: NodePort

Dockerコンテナをデプロイ

1. Podをデプロイ

作成したマニフェストファイルをkubectl applyコマンドで展開する。

# kubectl apply -f deployment-hello.yml
deployment.apps/hello-k8s-deployment created

問題なければ、以下のように3台のPodが展開される。NODEの項目を確認すると、各Podは別々のノードで起動していることがわかる。

# kubectl get pod -o=wide
NAME                                    READY   STATUS    RESTARTS   AGE   IP           NODE        NOMINATED NODE   READINESS GATES
hello-k8s-deployment-6c69965bcb-24qkv   1/1     Running   0          12s   10.244.0.6   t1051kube   <none>           <none>
hello-k8s-deployment-6c69965bcb-4bp74   1/1     Running   0          12s   10.244.2.4   t1053kube   <none>           <none>
hello-k8s-deployment-6c69965bcb-fkbpr   1/1     Running   0          12s   10.244.1.4   t1052kube   <none>           <none>

2. サービスリソースをデプロイ

サービスリソースも同様にkubectl applyコマンドで展開する。

# kubectl apply -f service-hello.yml
service/hello-k8s-service created

問題なければ、サービスリソースは以下の通り表示される。今回はPORTの項目 に記載されている31595ポートが接続用のポート番号となる。

# kubectl get service
NAME                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
hello-k8s-service   NodePort    10.102.109.11   <none>        8080:31595/TCP   31s
kubernetes          ClusterIP   10.96.0.1       <none>        443/TCP          24h

3. デプロイしたPodへ接続確認

それでは実際にサービスリソース経由でPodにアクセスをしてみよう。

接続先URLは以下の通り。今回はNodePortの設定となるため、接続先は任意のノードの物理IPアドレスとなる。ポート番号は、先ほど確認した31595ポートとなる。

  • http://[任意のノードの物理IPアドレス]:31595

試しにブラウザからノード#3に接続すると以下の通り表示された。

最上部にアクセス先のPodが表示されるており、hello-k8s-deployment-6c69965bcb-4bp74となっている。このことから、ノード#2で起動しているPodであり、たとえノード#3の物理IPアドレスにアクセスしたとしても、実際にアクセスするPodは同一ノードのものとは限らず、任意のPodが選ばれていることがわかる。

以上で、Kubernetes環境にマニフェストファイルを使ってDockerコンテナをデプロイする手順は完了となる。

2023年3月18日土曜日

Kubernetes構築手順② (ワーカーノードを追加)

前回、Kubernetesのコントロールプレーンを構築する手順を記載した。

本記事では、作成したKubernetesクラスターにワーカーノードを追加する手順を記載する。

環境

以下に今回構築する各種ソフトウェアのバージョンを記載する。

  • ホストOS : AlmaLinux 8.6
  • Docker : 23.0.1
  • cri-dockerd: 0.3.1-dev
  • Kubernetes: v1.26.2

今回の構成の概要図を以下に記載する。

ワーカーノードの構築

ワーカーノードの構築は、kubeadmコマンドを実行する直前までは、コントロールプレーンと同様の作業が必要となる。前回記事を参考にあらかじめ以下作業を実施しておこう。

Kubernetesクラスターへ参加

1. Tokenを確認

ワーカーノードをKubernetesクラスターへの参加させるため、kubeadm joinコマンドを実行する必要があるが、この際にコントロールプレーンが持つTokenの情報が必要となる。Tokenは、Kubernetesクラスターを作成した際に表示されるものとなる。

# kubeadm init --pod-network-cidr=10.244.0.0/16 --cri-socket=unix:///var/run/cri-dockerd.sock
[init] Using Kubernetes version: v1.26.2

~(中略)~

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.11.51:6443 --token bexxee.xx866gxx91sxxa69 \
        --discovery-token-ca-cert-hash sha256:06d8e3077c71a3f7af2xx8d6b389d43673xx9a8axxa5d003ed8dccb356a42f80

もし、クラスター作成時の情報が不明だったり、Tokenの有効期限が切れた場合は、以下コマンドを実行することでTokenを作成し表示させることができる。

# kubeadm token create --print-join-command
kubeadm join 192.168.11.51:6443 --token berssm.biqyhxls0jsdxxxx --discovery-token-ca-cert-hash sha256:c65f49b8ad89d2a2ee1790695a4d7fd0d5583e7f8a7e3a900e04cf5c2356xxxx

# kubeadm token list
TOKEN                     TTL         EXPIRES                USAGES                   DESCRIPTION                                                EXTRA GROUPS
3b4zsz.26fm7d17lb1jxxxx   3h          2023-03-04T23:54:16Z   authentication,signing   The default bootstrap token generated by 'kubeadm init'.   system:bootstrappers:kubeadm:default-node-token
berssm.biqyhxls0jsdxxxx   23h         2023-03-05T20:46:09Z   authentication,signing   <none>                                                     system:bootstrappers:kubeadm:default-node-token
[root@t1051kube ~]#

2. kubeadmコマンド実行

それではワーカーノードとしてKubernetesクラスターに参加させてみよう。

今回はCRIにcri-dockerdを用いるため、確認したTokenのコマンドに、--cri-socket=unix:///var/run/cri-dockerd.sockのオプションを追加し、kubeadm joinコマンドを実行する。
※なお、本作業はインターネット接続できない状態であっても、特にプロキシ設定などは行わずに実施できる。

# kubeadm join 192.168.11.51:6443 --token berssm.biqyhxls0jsdxxxx \
        --discovery-token-ca-cert-hash sha256:c65f49b8ad89d2a2ee1790695a4d7fd0d5583e7f8a7e3a900e04cf5c2356xxxx \
        --cri-socket=unix:///var/run/cri-dockerd.sock
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

3. Kubernetesクラスター状態確認

Kubernetesの管理はkubectlコマンドを使って実施するが、そのままでは使用できないので、環境変数で設定ファイルのパスを指定しておく。

# export KUBECONFIG=/etc/kubernetes/kubelet.conf

それでは、kubectlコマンドを使って、PodとNodeの状態を確認してみよう。以下の通り、kube-flannel-dskube-proxyのPodが各Nodeで起動しており、参加したワーカーノードはReadyとなっていれば成功となる。

# kubectl get pod -A -o=wide
NAMESPACE      NAME                                READY   STATUS    RESTARTS   AGE     IP              NODE        NOMINATED NODE   READINESS GATES
kube-flannel   kube-flannel-ds-8s4cq               1/1     Running   0          21h     192.168.11.51   t1051kube   <none>           <none>
kube-flannel   kube-flannel-ds-sfkg7               1/1     Running   0          4m40s   192.168.11.52   t1052kube   <none>           <none>
kube-system    coredns-787d4945fb-cf2sf            1/1     Running   0          21h     10.244.0.2      t1051kube   <none>           <none>
kube-system    coredns-787d4945fb-wkp86            1/1     Running   0          21h     10.244.0.3      t1051kube   <none>           <none>
kube-system    etcd-t1051kube                      1/1     Running   0          21h     192.168.11.51   t1051kube   <none>           <none>
kube-system    kube-apiserver-t1051kube            1/1     Running   0          21h     192.168.11.51   t1051kube   <none>           <none>
kube-system    kube-controller-manager-t1051kube   1/1     Running   0          21h     192.168.11.51   t1051kube   <none>           <none>
kube-system    kube-proxy-lscpc                    1/1     Running   0          21h     192.168.11.51   t1051kube   <none>           <none>
kube-system    kube-proxy-vz4v8                    1/1     Running   0          4m40s   192.168.11.52   t1052kube   <none>           <none>
kube-system    kube-scheduler-t1051kube            1/1     Running   0          21h     192.168.11.51   t1051kube   <none>           <none>

# kubectl get node
NAME        STATUS   ROLES           AGE     VERSION
t1051kube   Ready    control-plane   21h     v1.26.2
t1052kube   Ready    <none>          4m43s   v1.26.2

最終的に1台のコントロールプレーンと2台のワーカーノードを追加いした場合は、以下のような状態となる。

# kubectl get pod -A -o=wide
NAMESPACE      NAME                                READY   STATUS    RESTARTS   AGE     IP              NODE        NOMINATED NODE   READINESS GATES
kube-flannel   kube-flannel-ds-8s4cq               1/1     Running   0          21h     192.168.11.51   t1051kube   <none>           <none>
kube-flannel   kube-flannel-ds-mrpsm               1/1     Running   0          3m13s   192.168.11.53   t1053kube   <none>           <none>
kube-flannel   kube-flannel-ds-sfkg7               1/1     Running   0          11m     192.168.11.52   t1052kube   <none>           <none>
kube-system    coredns-787d4945fb-cf2sf            1/1     Running   0          21h     10.244.0.2      t1051kube   <none>           <none>
kube-system    coredns-787d4945fb-wkp86            1/1     Running   0          21h     10.244.0.3      t1051kube   <none>           <none>
kube-system    etcd-t1051kube                      1/1     Running   0          21h     192.168.11.51   t1051kube   <none>           <none>
kube-system    kube-apiserver-t1051kube            1/1     Running   0          21h     192.168.11.51   t1051kube   <none>           <none>
kube-system    kube-controller-manager-t1051kube   1/1     Running   0          21h     192.168.11.51   t1051kube   <none>           <none>
kube-system    kube-proxy-jfg8b                    1/1     Running   0          3m13s   192.168.11.53   t1053kube   <none>           <none>
kube-system    kube-proxy-lscpc                    1/1     Running   0          21h     192.168.11.51   t1051kube   <none>           <none>
kube-system    kube-proxy-vz4v8                    1/1     Running   0          11m     192.168.11.52   t1052kube   <none>           <none>
kube-system    kube-scheduler-t1051kube            1/1     Running   0          21h     192.168.11.51   t1051kube   <none>           <none>

# kubectl get node
NAME        STATUS   ROLES           AGE     VERSION
t1051kube   Ready    control-plane   21h     v1.26.2
t1052kube   Ready    <none>          11m     v1.26.2
t1053kube   Ready    <none>          3m18s   v1.26.2

参考:コントロールプレーンにおいても管理用Pod「以外」を起動させる設定 (taintの解除)

初期設定時は、コントロールプレーンにおいては管理用Podのみ起動できる設定が入っている。これは「taint (汚れ、汚染という意味)」と呼ばれる設定において制御されている。

検証用途などにおいては、コントロールプレーンにおいても管理用Pod「以外」を起動したい場合は、以下コマンドでtaintを解除する。
※今回は説明しないが、Pod側の設定で「toleration (耐える、黙認という意味)」という対となる設定をすることでも対処できる。

# kubectl describe node t1051kube | grep Taints
Taints:             node-role.kubernetes.io/control-plane:NoSchedule

# kubectl taint node t1051kube node-role.kubernetes.io/control-plane:NoSchedule-
node/t1051kube untainted

# kubectl describe node t1051kube | grep Taints
Taints:             <none>

もし、taintの設定を戻したい場合は以下コマンドを実行する。

# kubectl taint node t1051kube node-role.kubernetes.io/control-plane:NoSchedule
node/t1051kube tainted

以上で、Kubernetesクラスターにワーカーノードを追加する手順は完了となる。次回は、本環境に実際にDockerコンテナをPodとしてデプロイし、外部からアクセスできることを確認する。

2023年2月18日土曜日

minikubeで構築したKubernetes環境にて、DockerのコンテナイメージをPodとして動かす

先日、minikubeを使ってKubernetes環境を構築し、テスト用のコンテナを動作させるところまで記事にした。

次は自分でビルドしたDcokerのコンテナイメージをminikubeで起動させてみたいと思う。

本記事では、minikubeで構築したKubernetes環境にて、DockerのコンテナイメージをPodとして動かすための手順を記載する。

環境

以下に今回構築する各種ソフトウェアのバージョンを記載する。

  • ホストOS : AlmaLinux 8.6 (GUI環境を含めインストールする)
  • ホストDocker : 20.10.21
  • minikube : 1.28.0

以下にminikubeの環境の構成概要図を記載する。

Dockerコンテナイメージ作成

1. コンテナイメージをビルドするためのDockerfileの準備

今回用意するコンテナイメージは、過去の記事で作成したSquidが動作するプロキシサーバ用コンテナイメージを使用する。このコンテナイメージをビルドしminikube上で起動させ、インターネット上のWeb閲覧ができることを確認する。

2. Dockerクライアントの接続先を変更

Dockerクライアントが接続するDockerをOS上のDocker(unix:///var/run/docker.sock)ではなく、minikube上のDocker(tcp://192.168.49.2:2376)に変更する。この作業を実施しないと、minikubeがコンテナをPullできず「ErrImagePull」や「ImagePullBackOff」のエラーとなりPodが起動できないので注意しよう。

Dockerクライアントの接続先は環境変数で指定されている。minikubeのコマンドを使うことで環境変数を設定解除及び設定することができる。
※厳密には設定のためのコマンドを表示するだけなので、evalコマンドに渡して実行させる必要がある。

minikube用の環境変数を「設定」するコマンド

$ minikube -p minikube docker-env
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.49.2:2376"
export DOCKER_CERT_PATH="/home/kubeuser/.minikube/certs"
export MINIKUBE_ACTIVE_DOCKERD="minikube"

# To point your shell to minikube's docker-daemon, run:
# eval $(minikube -p minikube docker-env)

minikube用の環境変数を「設定解除」するコマンド

$ minikube -p minikube docker-env -u
unset DOCKER_TLS_VERIFY;
unset DOCKER_HOST;
unset DOCKER_CERT_PATH;
unset MINIKUBE_ACTIVE_DOCKERD;

コマンド実行結果は以下の通りとなる。なお、すでに接続先がminikube上のDockerとなっていた場合は、本作業はスキップすること。

$ docker context ls
NAME        DESCRIPTION                               DOCKER ENDPOINT               KUBERNETES ENDPOINT                   ORCHESTRATOR
default *   Current DOCKER_HOST based configuration   unix:///var/run/docker.sock   https://192.168.49.2:8443 (default)   swarm

$ eval $(minikube -p minikube docker-env)

$ docker context ls
NAME        DESCRIPTION                               DOCKER ENDPOINT           KUBERNETES ENDPOINT                   ORCHESTRATOR
default *   Current DOCKER_HOST based configuration   tcp://192.168.49.2:2376   https://192.168.49.2:8443 (default)   swarm
Warning: DOCKER_HOST environment variable overrides the active context. To use a context, either set the global --context flag, or unset DOCKER_HOST environment variable.

3. コンテナイメージをビルド

コンテナイメージをビルドしよう。通常のDockerfileを使ったビルド手順と同じく、以下のようにDockerfileが配置されているディレクトリに移動したのち、docker buidを実行すれば問題ない。

$ cd ~/almalinux-squid/
$ docker build -t almalinux-squid:8.7 .

ビルドしたコンテナイメージを確認しておく。

$ docker images
REPOSITORY                                TAG       IMAGE ID       CREATED              SIZE
almalinux-squid                           8.7       7dffc71b1972   2 minutes ago        293MB
almalinux                                 8.7       acaca326f3b3   9 days ago           190MB

~(以下略)~

PodとServiceリソースの作成

1. コンテナイメージからPodを作成

今回のPodやServiceリソースを作成するためのnamespaceとして、「mynamespace」を作成する。

$ kubectl create namespace mynamespace
namespace/mynamespace created

$ kubectl get namespace
NAME              STATUS   AGE
default           Active   63d
kube-node-lease   Active   63d
kube-public       Active   63d
kube-system       Active   63d
mynamespace       Active   6s

先ほどビルドしたコンテナイメージをデプロイし、Podを作成する。

$ kubectl create deployment almalinux-squid --image=almalinux-squid:8.7 -n=mynamespace
deployment.apps/almalinux-squid created

$  kubectl get pod -n=mynamespace
NAME                               READY   STATUS    RESTARTS   AGE
almalinux-squid-7bcddbfd4b-8twsw   1/1     Running   0          10s

2. Serviceリソースを作成

PodにアクセスするためのServiceリソースを作成する。

$ kubectl expose deployment almalinux-squid --type=NodePort --port=8080 -n=mynamespace
service/almalinux-squid exposed

作成されたServiceリソースの情報を確認し、コンテナへ接続するURL(IPアドレスとポート番号)を確認してみよう。

$ kubectl get services almalinux-squid -n=mynamespace
NAME              TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
almalinux-squid   NodePort   10.98.44.98   <none>        8080:32622/TCP   32s

まず、TYPEがNodePortとなるので、minikubeのNodeのIPアドレスである「192.168.49.2」がアクセス対象のIPアドレスとなる。ポート番号は、サービスリソース作成時に決定されるが、今回は32622/TCPとなっていることがわかる。以上より、コンテナのSquidへの接続URLは、http://192.168.49.2:32622となる。

接続先情報はServiceリソースの内容からも確認できるが、minikubeコマンドを使えばもっと簡単に確認することができる。

$ minikube service almalinux-squid --url -n=mynamespace
http://192.168.49.2:32622

3. 動作確認

先ほど確認したURLをminikubeが動作するLinux上のFirefoxのプロキシサーバとして設定する。

試しにGoogleに接続してみたとこと、問題なくプロキシ経由で表示することができた。

以上で、minikubeで構築したKubernetes環境にて、DockerコンテナイメージをPodとして動かすための手順は完了となる。

2023年1月7日土曜日

「minikube」を使ってKubernetes検証環境を構築する手順

コンテナのオーケストレーションツールのデファクトスタンダードとなっているKubernetesは、仕組みが複雑であり、マニュアルや書籍を見るだけでは、なかなか理解を深めるのが難しい。

インフラ技術を理解するためには、実際に構築して操作することが一番早いと考えており、自宅検証環境にKubernetes環境を構築することにした。

今回は、Linux OS上に容易にKubernetes検証環境を構築できる「minikube」をインストールする手順を記載する。また、minikube起動後に、簡単なコンテナを作成し外部からアクセスするまでの流れを確認してみよう。

環境

以下に今回構築する各種ソフトウェアのバージョンを記載する。

  • ホストOS : AlmaLinux 8.6 (GUI環境を含めインストールする)
  • ホストDocker : 20.10.21
  • minikube : 1.28.0

minikubeを動作させるためのリソース要件は以下の通り。今回は、CPU 4コア、メモリ 4GB、ディスク 20GBで構成した。また、インターネット接続はプロキシ(私の環境の場合はhttp://192.168.33.23:8080)経由での接続が必要となるため、必要なプロキシ設定も手順に記載している。プロキシ設定が不要な場合は、手順を飛ばしてもらえれば問題ない。

  • 2 CPUs or more
  • 2GB of free memory
  • 20GB of free disk space
  • Internet connection

minikubeはホストOSのDockerやVirtualBoxを用いて、Kubernetesのノードを構成することで、Kubernetes環境を即座にスクラップ&ビルドしながら検証をすることができる。

以下にminikubeの環境の構成概要図を記載する。

minikubeインストール手順

1. プロキシ設定 (必要な場合のみ)

私の環境ではプロキシ経由でなければインターネット接続ができないため、以下の通り環境変数を設定する。プロキシの環境変数について小文字と大文字の両方を設定している理由は、dnfコマンドでは小文字の環境変数の設定が必要であり、minikubeの場合は大文字の環境変数の設定が必要となるためである(とてもややこしい)。

# export http_proxy=http://192.168.33.23:8080
# export https_proxy=http://192.168.33.23:8080
# export no_proxy=192.168.0.0/16
# export HTTP_PROXY=http://192.168.33.23:8080
# export HTTPS_PROXY=http://192.168.33.23:8080
# export NO_PROXY=192.168.0.0/16

2. Dockerインストール前の競合パッケージの削除

minikubeはノードをDockerコンテナやVirtualBoxの仮想マシンとして構築する。今回はDockerをドライバーとして利用することとし、まずは、Dockerをインストールする。

ただし、GUI環境をインストールしたAlmaLinuxの場合、以下の通りpodmanとcontainers-commonのパッケージが競合する旨のエラーでインストールに失敗する。

# dnf install docker-ce docker-ce-cli containerd.io -y
メタデータの期限切れの最終確認: 0:05:01 時間前の 2022年11月26日 12時46分04秒 に 実施しました。
エラー:
 問題 1: インストール済パッケージの問題 podman-2:4.0.2-6.module_el8.6.0+2878+e681bc44.x86_64
  - パッケージ podman-2:4.0.2-6.module_el8.6.0+2878+e681bc44.x86_64 には runc >= 1.0.0-57 が必要ですが、どのプロバイダーからもインストールできません
  - パッケージ podman-3:4.2.0-4.module_el8.7.0+3344+484dae7b.x86_64 には runc >= 1.0.0-57 が必要ですが、どのプロバイダーからもインストールできません

~(中略)~

 問題 2: インストール済パッケージの問題 containers-common-2:1-27.module_el8.6.0+2878+e681bc44.x86_64
  - パッケージ containers-common-2:1-27.module_el8.6.0+2878+e681bc44.x86_64 には runc が必要ですが、どのプロバイダーからもインストールできません
  - パッケージ containers-common-2:1-43.module_el8.7.0+3344+484dae7b.x86_64 には runc が必要ですが、どのプロバイダーからもインストールできません

~(中略)~

このような場合は、一度podmanとcontainers-commonのパッケージを削除したうえで、Dockerをインストールしよう。

# dnf remove podman containers-common

3. Dockerをインストール

Dockerのインストールは以下の通りコマンドを実行すればよい。

# dnf install yum-utils -y
# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# dnf install docker-ce docker-ce-cli containerd.io -y

プロキシ環境の場合は、外部からコンテナのダウンロードができるよう、systemctlの起動設定に環境変数の設定をしておくこと。

# sed -ie '/\[Service\]/a Environment="http_proxy=http://192.168.33.23:8080" "https_proxy=http://192.168.33.23:8080" "no_proxy=192.168.0.0/16"' /usr/lib/systemd/system/docker.service

インストール完了後、Dockerのサービスを起動しておく。

# systemctl start docker
# systemctl enable docker

4. minikubeインストール

minikubeのインストールは、rpmをダウンロードしインストールするだけで完了する。

# curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-latest.x86_64.rpm
# rpm -Uvh minikube-latest.x86_64.rpm

5. minikube操作用ユーザの作成

minikubeのDockerドライバーはroot権限で操作できないため、操作用ユーザを作成する。参考情報として、もしroot権限でminikubeを起動すると、以下のようなメッセージが表示され、起動に失敗する。

X DRV_AS_ROOT が原因で終了します: 「docker」ドライバーは root 権限で使用すべきではありません。

今回はkubeuserというユーザを作成した。また、sudoが必要なコマンドがあるためwheelグループへの所属と、Dockerドライバーを操作するためにdockerグループへ所属させておく。

# useradd kubeuser
# usermod -aG wheel,docker kubeuser
# id kubeuser
uid=1000(kubeuser) gid=1000(kubeuser) groups=1000(kubeuser),10(wheel),974(docker)

6. minikubeを起動

以上で準備が整ったため、kubeuserにスイッチし、minikube startコマンドでminikubeを起動する。初回は、800MBほどのコンテナイメージのダウンロードが行われるため、時間を要するので気長に待とう。

# su - kubeuser

$ minikube start
* Almalinux 8.6 上の minikube v1.28.0
* docker ドライバーが自動的に選択されました
* root 権限を持つ Docker ドライバーを使用
* minikube クラスター中のコントロールプレーンの minikube ノードを起動しています
* ベースイメージを取得しています...
* ロード済み Kubernetes v1.25.3 をダウンロードしています...
    > preloaded-images-k8s-v18-v1...:  385.44 MiB / 385.44 MiB  100.00% 77.08 M
    > gcr.io/k8s-minikube/kicbase:  386.27 MiB / 386.27 MiB  100.00% 13.86 MiB
    > gcr.io/k8s-minikube/kicbase:  0 B [________________________] ?% ? p/s 24s
* docker container (CPUs=2, Memory=2200MB) を作成しています...
* ネットワークオプションが見つかりました:
  - HTTP_PROXY=http://192.168.33.23:8080
  - HTTPS_PROXY=http://192.168.33.23:8080
  - NO_PROXY=192.168.0.0/16
* Docker 20.10.20 で Kubernetes v1.25.3 を準備しています...
  - env HTTP_PROXY=http://192.168.33.23:8080
  - env HTTPS_PROXY=http://192.168.33.23:8080
  - env NO_PROXY=192.168.0.0/16
  - 証明書と鍵を作成しています...
  - コントロールプレーンを起動しています...
  - RBAC のルールを設定中です...
* Kubernetes コンポーネントを検証しています...
  - gcr.io/k8s-minikube/storage-provisioner:v5 イメージを使用しています
* 有効なアドオン: default-storageclass, storage-provisioner
* kubectl が見つかりません。kubectl が必要な場合、'minikube kubectl -- get pods -A' を試してください
* 終了しました!kubectl がデフォルトで「minikube」クラスターと「default」ネーム スペースを使用するよう設定されました

7. kubectlコマンドのエイリアスを設定

Kubernetes環境を操作するためのkubectlコマンドはminikubeには用意されておらず、minikube kubectl -- [コマンド]といったコマンドを実行する必要がある。

コマンドの簡略化と本来のKubernetes環境の操作に近づけることを目的として、エイリアスを設定しておく。

$ echo 'alias kubectl="minikube kubectl --"' >> ~/.bashrc
$ source ~/.bashrc

8. 起動状態の確認

minikube起動後のノードとPodの状態を確認しておこう。

ノードは通常1台のみ起動しているはずだ。詳細は省くが、minikubeをマルチノード構成としたい場合は、minikube start --nodes=3といった形でノード数を指定することで、複数ノードで起動させることができる。

$ kubectl get node -o=wide
NAME       STATUS   ROLES           AGE   VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION              CONTAINER-RUNTIME
minikube   Ready    control-plane   10m   v1.25.3   192.168.49.2   <none>        Ubuntu 20.04.5 LTS   4.18.0-372.9.1.el8.x86_64   docker://20.10.20

PodとしてはKubernetes環境管理に必要となる各種Podが起動する。ステータスがRunningになっていれば問題ない。

$ kubectl get pod -A
NAMESPACE     NAME                               READY   STATUS    RESTARTS       AGE
kube-system   coredns-565d847f94-t7f4s           1/1     Running   0              2m22s
kube-system   etcd-minikube                      1/1     Running   0              2m35s
kube-system   kube-apiserver-minikube            1/1     Running   0              2m35s
kube-system   kube-controller-manager-minikube   1/1     Running   0              2m35s
kube-system   kube-proxy-2jzrw                   1/1     Running   0              2m22s
kube-system   kube-scheduler-minikube            1/1     Running   0              2m35s
kube-system   storage-provisioner                1/1     Running   1 (112s ago)   2m34s

動作確認

Kubernetesの動作確認としてにテスト用のコンテナを用いてPodを作成し、サービスとして公開してみよう。

再掲となるが、動作確認時におけるminikubeの内部構成は以下の図のようになる。

1. Podとサービスの起動確認

以下コマンドでPodを作成する。

$ kubectl create deployment hello-minikube --image=kicbase/echo-server:1.0
deployment.apps/hello-minikube created

$ kubectl get pod -o=wide
NAME                              READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
hello-minikube-7ddcbc9b8b-5g79b   1/1     Running   0          12s   172.17.0.3   minikube   <none>           <none>

作成したPodはそのままでは外部からアクセスすることができないため、Podと紐づけるサービスを作成する。なお、--type=NodePortを指定することで、ノードの持つIPアドレス(192.168.49.2)にてサービスを公開することができる。

$ kubectl expose deployment hello-minikube --type=NodePort --port=8080
service/hello-minikube exposed

$ kubectl get service -o=wide
NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE    SELECTOR
hello-minikube   NodePort    10.107.255.240   <none>        8080:31931/TCP   7s     app=hello-minikube
kubernetes       ClusterIP   10.96.0.1        <none>        443/TCP          102s   <none>

公開したサービスにアクセスしてみよう。ホストOSのブラウザを開いて、直接URLを入力してもよいが、minikubeコマンドを使用することで、サービスのURLを入力した状態でデフォルトのブラウザを起動させることができる。

$ minikube service hello-minikube
|-----------|----------------|-------------|---------------------------|
| NAMESPACE |      NAME      | TARGET PORT |            URL            |
|-----------|----------------|-------------|---------------------------|
| default   | hello-minikube |          80 | http://192.168.49.2:31931 |
|-----------|----------------|-------------|---------------------------| * デフォルトブラウザーで default/hello-minikube サービスを開いています... http://192.168.49.2:31931

2. 外部からサービスにアクセスさせるためのポートフォワード設定

minikubeのサービスに対しては、通常ホストOSでなければアクセスすることができないが、もし外部からアクセスさせたい場合は、以下の通りポートフォワードすることで実現できる。

なお、ポートフォワードはフォアグラウンドで実行されるため、終了する際はCtrl + Cで終了させること。

$ kubectl port-forward service/hello-minikube --address 0.0.0.0 8080:8080
Forwarding from 0.0.0.0:8080 -> 8080
Handling connection for 8080
Handling connection for 8080
^C ←★Ctrl + Cでプロセス終了

この状態の場合は、以下の通り外部からホストOSのIPアドレス(今回は192.168.11.52)でサービスにアクセスすることができる。

ポートフォワードをバックグラウンド実行させる場合は、以下の通り実行する。

$ kubectl port-forward service/hello-minikube --address 0.0.0.0 7080:80 > /dev/null 2>&1 &
[1] 33173

$ fg
minikube kubectl -- port-forward service/hello-minikube --address 0.0.0.0 7080:80 > /dev/null 2>&1
^C ←★Ctrl + Cでプロセス終了

以上で、Linux OS上に「minikube」をインストールする手順は完了となる。

minikube環境をリセットする

最後にminikube環境をリセットする方法を紹介しておこう。環境の削除は、minikube deleteコマンドを実行するだけで完了する。

$ minikube delete
  docker の「minikube」を削除しています...
  コンテナー「minikube」を削除しています...
  /home/kubeuser/.minikube/machines/minikube を削除しています...
  クラスター「minikube」の全てのトレースを削除しました。

削除後に再度minikube startすることで、再度きれいな状態でminikubeのKubernetes環境を利用することができる。

参考

2022年12月28日水曜日

OSSのコンテナレジストリ「Harbor」インストール手順

Docker Hubのようにコンテナイメージを格納し、Dockerにてイメージをダウンロード(Pull)して利用できるようにするサービスをコンテナリポジトリと呼ぶ。

Docker Hubはインターネット上で公開されたサービスとなり、誰でも自由に使える一方、インターネット環境であることからセキュリティ面におけるリスクも大きい。

そのような状況をふまえ、自宅検証環境にプライベートのコンテナレジストリを構築することにした。本記事では、OSSのコンテナレジストリ「Harbor」をインストールする手順を記載する。

なお、今回はHarborへのアクセスをHTTPによる構成としたが、自己署名証明書を使ってHTTPSにて通信させる場合は、以下記事を参照いただきたい。

環境

Harbor自体はDockerコンテナとして動作する。Harbor及びDockerが動作するOSとしてはAlmaLinuxを使用した。

  • OS : AlmaLinux release 8.6
  • Docker : 20.10.21
  • Docker Compose : v2.12.2
  • Harbor : v2.6.2
今回の作業の簡単な概要図を以下に記載する。

Dockerインストール

1. Dockerインストール

Harbor自体もDockerコンテナとして動作するため、まずはDockerのインストールを行う。

# dnf install yum-utils -y
# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# dnf install docker-ce docker-ce-cli containerd.io -y

プロキシ環境の場合は、インターネット接続できるようにsystemdに環境変数の設定を行う。

# sed -ie '/\[Service\]/a Environment="http_proxy=http://192.168.33.23:8080" "https_proxy=http://192.168.33.23:8080" "no_proxy=192.168.0.0/16"' /usr/lib/systemd/system/docker.service
# systemctl start docker
# systemctl enable docker

2. Docker composeのインストール

Harborはインストール時にDocker composeを利用するため、こちらもインストールする。Docker composeは以下の通りdnfコマンドでインストールすることができる。

# dnf install docker-compose-plugin -y

Docker composeのバージョンを確認しておく。

# docker compose version
Docker Compose version v2.12.2

本題とは逸れるが、Docker composeはもともとdocker-composeといったコマンド体系となっていたが、現在のDocker compose V2系では、dockerコマンドに統合されており、docker composeというハイフンなしのコマンド体系になっている。たとえば、docker-compose up -ddocker compose up -dで実行する必要があるので覚えておくとよいだろう。

Compose V2 integrates compose functions into the Docker platform, continuing to support most of the previous docker-compose features and flags. You can run Compose V2 by replacing the hyphen (-) with a space, using docker compose, instead of docker-compose.

Harborインストール

1. Harborのインストーラをダウンロード

Harborのインストーラは、オンラインインストーラとオフラインインストーラの2種類が用意されている。今回はオフラインインストーラを用いる。ダウンロードは以下URLからダウンロードすることができる。

名前に-rcN(Nは数字1桁)が付与されているものは、リリース候補版となる。今回はlatestタグの付与されているバージョン2.6.2をインストールすることにした。オフラインインストーラの容量は約760MBとなる。

2. インストーラを解凍

インストーラはtgz圧縮されているので解凍する。ファイル容量は大きいが、ファイル数自体は多くない。

# tar zxvf harbor-offline-installer-v2.6.2.tgz
harbor/harbor.v2.6.2.tar.gz
harbor/prepare
harbor/LICENSE
harbor/install.sh
harbor/common.sh
harbor/harbor.yml.tmpl

# ls -l harbor
合計 792320
-rw-r--r-- 1 root root     11347 11月  9 18:35 LICENSE
-rw-r--r-- 1 root root      3639 11月  9 18:35 common.sh
-rw-r--r-- 1 root root 811298774 11月  9 18:36 harbor.v2.6.2.tar.gz
-rw-r--r-- 1 root root     10649 11月  9 18:35 harbor.yml.tmpl
-rwxr-xr-x 1 root root      3171 11月  9 18:35 install.sh
-rwxr-xr-x 1 root root      1881 11月  9 18:35 prepare

3. インストール設定ファイル(YAML)を修正

Harborはインストールの設定ファイルとして、harbor.ymlというYAMLファイルの作成が必要となる。

解凍したインストーラ内部に、harbor.yml.tmplというテンプレートが存在するため、これをコピーしてharbor.ymlを作成する。

# cd harbor
# cp harbor.yml.tmpl harbor.yml

以下★箇所を最低限設定しておく。通常Harborへの接続としては、セキュリティの観点からHTTP通信ではなくHTTPS通信を使用すべきであるが、今回は手順簡略化のためHTTP通信による設定を行う。

その他のパラメータについては、公式ドキュメントを参照いただきたい。

harbor.yml

# Configuration file of Harbor

# The IP address or hostname to access admin UI and registry service.
# DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
hostname: 192.168.11.54 ←★ホスト名を設定する。DNSなどで名前解決できる場合はFQDN設定が望ましいが、今回はIPアドレスで設定する

# http related config
http:
  # port for http, default is 80. If https enabled, this port will redirect to https port
  port: 80

# https related config
#https: ←★原則はHTTPSによる通信が望ましいが、今回は手順簡略化のためHTTPを使用するためコメントアウト
  # https port for harbor, default is 443
#  port: 443 ←★原則はHTTPSによる通信が望ましいが、今回は手順簡略化のためHTTPを使用するためコメントアウト
  # The path of cert and key files for nginx
#  certificate: /your/certificate/path ★←SSLサーバ証明書を使用しないためコメントアウト
#  private_key: /your/private/key/path ★←SSLサーバ証明書を使用しないためコメントアウト

~(以下略)~

4. インストールスクリプトの実行

harbor.ymlの準備が整ったら、インストールスクリプトを実行する。[Step 0]から[Step 5]まで処理が順に実行される。最後の[Step 5]において、Docker composeによるコンテナ起動がされていることがわかる。

# ./install.sh

[Step 0]: checking if docker is installed ...

Note: docker version: 20.10.21

[Step 1]: checking docker-compose is installed ...

Note: Docker Compose version v2.12.2

[Step 2]: loading Harbor images ...
Loaded image: goharbor/harbor-jobservice:v2.6.2
Loaded image: goharbor/trivy-adapter-photon:v2.6.2
Loaded image: goharbor/chartmuseum-photon:v2.6.2
Loaded image: goharbor/redis-photon:v2.6.2
Loaded image: goharbor/nginx-photon:v2.6.2
Loaded image: goharbor/notary-signer-photon:v2.6.2
Loaded image: goharbor/harbor-core:v2.6.2
Loaded image: goharbor/harbor-db:v2.6.2
Loaded image: goharbor/harbor-registryctl:v2.6.2
Loaded image: goharbor/harbor-exporter:v2.6.2
Loaded image: goharbor/prepare:v2.6.2
Loaded image: goharbor/registry-photon:v2.6.2
Loaded image: goharbor/notary-server-photon:v2.6.2
Loaded image: goharbor/harbor-portal:v2.6.2
Loaded image: goharbor/harbor-log:v2.6.2


[Step 3]: preparing environment ...

[Step 4]: preparing harbor configs ...
prepare base dir is set to /root/harbor
WARNING:root:WARNING: HTTP protocol is insecure. Harbor will deprecate http protocol in the future. Please make sure to upgrade to https
Generated configuration file: /config/portal/nginx.conf
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/log/rsyslog_docker.conf
Generated configuration file: /config/nginx/nginx.conf
Generated configuration file: /config/core/env
Generated configuration file: /config/core/app.conf
Generated configuration file: /config/registry/config.yml
Generated configuration file: /config/registryctl/env
Generated configuration file: /config/registryctl/config.yml
Generated configuration file: /config/db/env
Generated configuration file: /config/jobservice/env
Generated configuration file: /config/jobservice/config.yml
Generated and saved secret to file: /data/secret/keys/secretkey
Successfully called func: create_root_cert
Generated configuration file: /compose_location/docker-compose.yml
Clean up the input dir


Note: stopping existing Harbor instance ...


[Step 5]: starting Harbor ...
[+] Running 10/10
 ? Network harbor_harbor        Created                                    0.0s
 ? Container harbor-log         Started                                    0.3s
 ? Container harbor-db          Started                                    0.9s
 ? Container registry           Started                                    1.0s
 ? Container registryctl        Started                                    0.9s
 ? Container harbor-portal      Started                                    1.0s
 ? Container redis              Started                                    1.0s
 ? Container harbor-core        Started                                    1.4s
 ? Container nginx              Started                                    2.2s
 ? Container harbor-jobservice  Started                                    2.1s
? ----Harbor has been installed and started successfully.----

もし、インストールスクリプト実行後にharbor.ymlを修正した場合は、再度インストールスクリプトを実行することで設定反映ができる。再実行の場合は、一度コンテナが削除されたのち、新しいコンテナが起動される。

# ./install.sh

[Step 0]: checking if docker is installed ...

Note: docker version: 20.10.21

[Step 1]: checking docker-compose is installed ...

Note: Docker Compose version v2.12.2

~(中略)~

Note: stopping existing Harbor instance ...
[+] Running 10/9
 ? Container nginx              Removed                                    0.1s
 ? Container harbor-jobservice  Removed                                    0.1s
 ? Container registryctl        Removed                                   10.1s
 ? Container harbor-portal      Removed                                    0.1s
 ? Container harbor-core        Removed                                    0.1s
 ? Container redis              Removed                                    0.3s
 ? Container harbor-db          Removed                                    0.3s
 ? Container registry           Removed                                    0.3s
 ? Container harbor-log         Removed                                   10.1s
 ? Network harbor_harbor        Removed                                    0.0s


[Step 5]: starting Harbor ...
[+] Running 10/10
 ? Network harbor_harbor        Created                                    0.0s
 ? Container harbor-log         Started                                    0.3s
 ? Container registryctl        Started                                    0.6s
 ? Container harbor-portal      Started                                    1.1s
 ? Container registry           Started                                    1.0s
 ? Container redis              Started                                    1.1s
 ? Container harbor-db          Started                                    1.0s
 ? Container harbor-core        Started                                    1.2s
 ? Container harbor-jobservice  Started                                    1.7s
 ? Container nginx              Started                                    1.7s
? ----Harbor has been installed and started successfully.----

5. DockerをHTTP接続に対応させる設定

Dockerは標準では、コンテナレジストリに対してHTTPSによる接続を行うため、HTTPによる接続をできるよう、/etc/docker/daemon.jsonのファイルを新規作成する。

記載しているIPアドレスは、harbor.ymlhostnameの設定と合わせればよく、IPアドレスまたはFQDNで設定することができる。

# ls -l /etc/docker/daemon.json
ls: '/etc/docker/daemon.json' にアクセスできません: そのようなファイルやディレクトリはありません
# cat << EOF > /etc/docker/daemon.json
{
  "insecure-registries": [
    "192.168.11.54"
  ]
}
EOF

設定後は、Docker及びHarborの再起動が必要となるため、以下の通り再起動を行う。

# systemctl restart docker
# docker compose down -v
# docker compose up -d

6. Web管理画面にログイン

HarborのWeb管理画面にログインする。

  • ユーザ : admin
  • 初期パスワード : Harbor12345
  • 接続先 : http://[HarborをインストールしたOSのIPアドレス]

動作確認

1. プロジェクトを作成

Harborではプロジェクトを作成し、そこにコンテナイメージを保存して管理する構成となっている。デフォルトでlibraryという名称のプロジェクトが存在するが、今回はあえて新規にmyprojectという名称のプロジェクトを作成した。

プロジェクトを作成の際の設定値は以下の通り。

設定項目 設定値 説明
Project Name myproject 任意の名前で設定する。
Access Level Public アクセス権はPublicとする。Publicの場合は、Pullする際にdocker loginコマンドによる認証が不要となる。逆にPublicにしない場合(Privateにする場合)は、Pullの際にdocker loginコマンドによる認証が必要となる。なお、Pushの際はいずれの権限においても事前の認証が必要となる。
Storage Quota -1 GiB 容量の制限(クォータ)の設定となる。今回はデフォルトの無制限(-1)とする。
Proxy Cache 無効 プロキシキャッシュの機能は無効化する。プロキシキャッシュの詳細は、公式マニュアルを参照いただきたい。

2. テスト用コンテナイメージのPull

それでは、Harborを使ってコンテナイメージのアップロード(Push)とダウンロード(Pull)ができることを確認しよう。なお、Push及びPullを行うDockerは、Harborとは別のサーバにインストールしたものとする。

テスト用のコンテナイメージはoraclelinux:8.7を用いる。このコンテナイメージをHarborへPushし、その後一度コンテナイメージを削除してから、HarborよるPullできることを確認する。

まずは、oraclelinux:8.7のコンテナイメージをDocker HubよりPullする。

# docker pull oraclelinux:8.7
8.7: Pulling from library/oraclelinux
4c770e098606: Pull complete
Digest: sha256:07a995ecaf9db1ce613648a08facc162de69f26c39712f1acc93629c2e6c4e73
Status: Downloaded newer image for oraclelinux:8.7
docker.io/library/oraclelinux:8.7

# docker images
REPOSITORY    TAG       IMAGE ID       CREATED       SIZE
oraclelinux   8.7       b0045ea7bbde   10 days ago   225MB

3. DockerをHTTP接続に対応させる設定

Dockerは標準では、コンテナレジストリに対してHTTPSによる接続を行うため、HTTPによる接続をできるよう、/etc/docker/daemon.jsonのファイルを新規作成する。

# ls -l /etc/docker/daemon.json
ls: '/etc/docker/daemon.json' にアクセスできません: そのようなファイルやディレクトリはありません
# cat << EOF > /etc/docker/daemon.json
{
  "insecure-registries": [
    "192.168.11.54"
  ]
}
EOF

設定後は、Dockerの再起動が必要となるため、以下の通り再起動を行う。

# systemctl restart docker

4. Harborへの認証

Pushする場合は、事前にdocker loginコマンドにてHarborに対して認証を成功させておく必要がある。ここで入力するユーザ名とパスワードは、Web管理画面と同じadmin / Harbor12345となる。

# docker login 192.168.11.54
Username: admin
Password: ←★"Harbor12345"を入力
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

5. コンテナイメージをPush

Pushするコンテナイメージに対して、タグの設定を行う。タグは以下の形式で設定する。

[HarborのIPアドレスまたはFQDN]/[プロジェクト名]:[タグ名]

実行結果を以下に記載する。

# docker tag oraclelinux:8.7 192.168.11.54/myproject/oraclelinux:8.7
# docker images
REPOSITORY                            TAG       IMAGE ID       CREATED       SIZE
192.168.11.54/myproject/oraclelinux   8.7       b0045ea7bbde   10 days ago   225MB
oraclelinux                           8.7       b0045ea7bbde   10 days ago   225MB

タグを付与したコンテナイメージをPushする。

# docker push 192.168.11.54/myproject/oraclelinux:8.7
The push refers to repository [192.168.11.54/myproject/oraclelinux]
d8c569c85182: Pushed
8.7: digest: sha256:89787c72978339a100b1855de3ab7749f29752fc83302456bfac6ba209008401 size: 529

特に問題が発生しなければ、HarborのWeb管理画面からも、Pushしたコンテナイメージを確認することができるはずだ。

6. コンテナイメージを削除

次に、先ほどPushしたコンテナイメージをPullしてみよう。

まずは、ローカルに存在するコンテナイメージを削除する。

# docker images
REPOSITORY                            TAG       IMAGE ID       CREATED       SIZE
192.168.11.54/myproject/oraclelinux   8.7       b0045ea7bbde   10 days ago   225MB
oraclelinux                           8.7       b0045ea7bbde   10 days ago   225MB

# docker rmi b0045ea7bbde -f
Untagged: 192.168.11.54/myproject/oraclelinux:8.7
Untagged: 192.168.11.54/myproject/oraclelinux@sha256:89787c72978339a100b1855de3ab7749f29752fc83302456bfac6ba209008401
Untagged: oraclelinux:8.7
Untagged: oraclelinux@sha256:07a995ecaf9db1ce613648a08facc162de69f26c39712f1acc93629c2e6c4e73
Deleted: sha256:b0045ea7bbde263d0543ac9efb749e588d3538bc673f98fe00a73006838a9b89
Deleted: sha256:d8c569c851824688f0f55d46d659a8eef6b8af3ed0a20f389b066f16a4a250e5

# docker images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

7. HarborよりコンテナイメージをPull

HarborよりコンテナイメージをPullする。

# docker pull 192.168.11.54/myproject/oraclelinux:8.7
8.7: Pulling from myproject/oraclelinux
4c770e098606: Pull complete
Digest: sha256:89787c72978339a100b1855de3ab7749f29752fc83302456bfac6ba209008401
Status: Downloaded newer image for 192.168.11.54/myproject/oraclelinux:8.7
192.168.11.54/myproject/oraclelinux:8.7

# docker images
REPOSITORY                            TAG       IMAGE ID       CREATED       SIZE
192.168.11.54/myproject/oraclelinux   8.7       b0045ea7bbde   10 days ago   225MB

Pullに成功すると、Harbor上でもPullが実行された回数が更新される。

以上で、OSSのコンテナレジストリ「Harbor」をインストールする手順は完了となる。

参考

人気の投稿