$ kubectl -n $(id -un) get pod -l app=harbor-nginx -o wide
概要
PVCの使い方を学習するために、Harborの説明に使用した harbor-nginx を使っていきます。
2つのPodから成るnginxクラスターを構成した時に、コンテンツを管理するためには、2台のPodの/usr/share/nginx/html/以下を管理する必要があります。(具体的には、両方のPodの/usr/share/nginx/html/以下を同一にする必要がある)
現状の確認と準備作業
作業を始める前に、SCCPのトップページに戻り、kubectlコマンドを使うための準備作業 を完了してください。
次に、前提となる設定が行なわれているか確認します。
pod/harbor-nginxの確認
実際はDeployment定義からReplicaSet定義が生成され、これによりPodが作成されていますが、ここでは実体であるPodの状況を確認します。
次のように2つのPodの状況が出力されれば成功です。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
READINESS GATES
harbor-nginx-6cc7576bc-kkc8q 1/1 Running 0 5h34m 10.233.105.70 u109ls04 <none> <none>
harbor-nginx-6cc7576bc-vbzgt 1/1 Running 0 5h34m 10.233.112.164 u109ls03 <none> <none>
表示されない場合には、Harbor - my-nginxイメージの登録 から最後までの作業を完了してから進めてください。
pod/poroxy の確認
まず `app: my-proxy
が稼動しているか確認します。
なお詳細は、リバース・プロキシー を確認してください。
$ kubectl -n $(id -un) get pod -l app=my-proxy
次のようにPod(proxy-XXXXXX-XXX)が表示されれば、次を飛して作業を進めてください。
NAME READY STATUS RESTARTS AGE
proxy-755bf9945f-jwqtn 1/1 Running 0 76m
画面にPodが表示されなかった場合は、次のコマンドを実行して、proxyを稼動させてから進めてください。
$ kubectl -n $(id -un) apply -f https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/setupk8s-centos/deploy-proxy.yaml
app: my-proxy
が稼動していても、svc/<namespace>-svc
の内容が proxy を向いていない可能性があるので、次のコマンドで svc/<namespace-svc
定義を更新します。
$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/volumes/svc-proxy.yaml" | sed -e "s/s12xxxxx/$(id -un)/" | kubectl -n $(id -un) apply -f -
これら deploy-proxy.yaml, svc-proxy.yaml のYAMLファイルは繰り返し、kubectlコマンドで適用しても問題ありませんので、なんとなく実行してしまっても問題ありません。
ここまでの確認
ここに到達している人は次の作業が完了しているはずです。
-
Harbor(https://inovtst9.u-aizu.ac.jp/)にmy-nginx:1.0が登録されている
-
Kubernetes上で、
app: harbor-nginx
とapp: my-proxy
が稼動している -
<namespace>-svc が selectorで、
app: my-proxy
を向いている
ここからの目標
準備作業が終ったところで、PVC(Filesystem/FileStorage)を利用し、2つ以上の pod/harbor-nginx から同時に参照できるコンテンツ領域を準備します。
そして、可能であれば外部からコンテンツを配置できるような仕組みを準備しましょう。
全体の構成は以下のようになります。
PVCについては記述していませんが、Pod#1, Pod#2の(nginx)から、1つのPVCを参照するようにします。
PVCの準備
ここでは、PVとPVC で利用したPVC、myfs-pvc
を利用します。
次のコマンドで、myfs-pvc
があることを確認します。
$ kubectl -n $(id -un) get pvc
次のように表示されれば問題ありません。次の myfs-pvc を作成する手順はスキップして、次に進みます。
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
myfs-pvc Bound pvc-8bb6ede5-fa54-4d77-b576-408072630231 10Gi RWX rook-cephfs 5m23s
もし、表示されない場合は次の要領で、myfs-pvc
を作成して次に進みます。
$ kubectl -n $(id -un) apply -f https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/volumes/pvc-cephfs.yaml
harbor-nginx からの myfs-pvc の利用
まず、pod/harbor-nginx を定義した時のYAMLファイルを確認します。
Harbor - KubernetesからのHarborの利用 に記載されている、deploy-nginx.yaml ファイルの内容を確認します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: harbor-nginx
spec:
selector:
matchLabels:
app: harbor-nginx
replicas: 2
template:
metadata:
labels:
app: harbor-nginx
spec:
containers:
- name: harbor-nginx
image: inovtst9.u-aizu.ac.jp/s12xxxxx/my-nginx:1.0
ports:
- containerPort: 80
ここに、PVとPVC で利用した deploy-nginx-cephfs.yaml ファイルに書かれていた、volumeMounts
と volumes
の定義を書き写します。
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-cephfs
spec:
replicas: 2
selector:
matchLabels:
app: nginx-cephfs
template:
metadata:
labels:
app: nginx-cephfs
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: "Always"
ports:
- containerPort: 80
volumeMounts:
- name: nginx-data-storage
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-data-storage
persistentVolumeClaim:
claimName: myfs-pvc
まずこの2つのファイルをダウンロードします。 そして、emacsなどのエディタで開き、よく見比べてください。
最初の ./harbor/deploy-nginx.yaml の下に、2番目の ../volumes/deploy-nginx-cephfs.yaml にある volumeMounts
から下の行全てをコピーします。
apiVersion: apps/v1
kind: Deployment
metadata:
name: harbor-nginx
spec:
selector:
matchLabels:
app: harbor-nginx
replicas: 2
template:
metadata:
labels:
app: harbor-nginx
spec:
containers:
- name: harbor-nginx
image: inovtst9.u-aizu.ac.jp/s12xxxxx/my-nginx:1.0
ports:
- containerPort: 80
volumeMounts:
- name: nginx-data-storage
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-data-storage
persistentVolumeClaim:
claimName: myfs-pvc
このような内容のファイルを適当な名前をつけてローカルファイルシステムに保存します。
そして、そのファイルを末尾に指定するような $ kubectl -n $(id -un) apply -f
コマンドを実行します。
実行例は以下のとおりです。
$ sed -e "s/s12xxxxx/$(id -un)/" deploy-harbor-nginx-with-myfs-pvc.yaml | kubectl -n $(id -un) apply -f -
deployment.apps/harbor-nginx configured
ここまでで、harbor-nginx は myfs-pvc を利用するように構成されているはずです。
自信のない人は、次のファイルを利用しても構いません。
$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/tutorial-nginx-pvc/deploy-harbor-nginx-with-myfs-pvc.yaml" | sed -e "s/s12xxxxx/$(id -un)/" | kubectl -n $(id -un) apply -f -
ProxyのConfigMapの更新
Proxyから app: harbor-nginx
に処理を向ける必要があります。
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-conf
data:
proxy.conf: |
server {
listen 80;
location /s12xxxxx/ {
proxy_pass http://harbor-nginx/;
}
}
このファイルを次の要領で適用します。
$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/tutorial-nginx-pvc/configmap-proxy-to-harbor-nginx.yaml" | sed -e "s/s12xxxxx/$(id -un)/" | kubectl -n $(id -un) apply -f -
このファイルが無事に適用できたら、app: my-proxy
を再起動します。
$ kubectl -n $(id -un) delete pod -l app=my-proxy
最後に、無事に稼動しているか、以下の自分のIDのリンクを辿ってみてください。
コンテンツが配置されていない場合は、動いているか分かりませんが、つぎの要領で、app: harbor-nginx
のログを確認して、Webブラウザからのアクセスがあることを確認してください。
$ kubectl -n $(id -un) logs -l app=harbor-nginx
deploymentを経由することで、2つのpod両方のログを表示させています。
10.233.112.220 - - [12/Jul/2021:08:19:58 +0000] "GET / HTTP/1.0" 304 0 "https://web-int.u-aizu.ac.jp/" "Mozill
a/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0" "192.168.100.53"
ユーザーリスト
コンテンツ(htmlファイル等)の確認と配置について
ここから先の作業は、ゼミ室10のネットワーク(192.168.100.0/24)の内部でないと、最終的に構築したSSHサーバーにアクセスできません。(rsyncコマンド)の実行に失敗します。
ここまででは、自由にコンテンツを配布できるWebサーバーが入手できた感じはあまりません。
特に pvc/myfs-pvc
にファイルを配置していない場合には、やっぱり何をしたか実感がわかないと思います。
使用した pvc/myfs-pvc
は、他のPodからも利用(mount)することができます。
ここから先では、ファイル更新用のSSHサーバーを準備して、rsyncなどを利用して、ローカルで準備したファイルを更新してみます。
このために利用するSSHサーバーのイメージをHarborに登録しました。
この使い方について、説明していきます。
設定ファイル
このSSHサーバーは次のようなDockerfileから構成されています。
FROM alpine:3.13.5
MAINTAINER YasuhiroABE <yasu-abe@u-aizu.ac.jp>
## openrc
RUN apk --no-cache add tzdata bash ca-certificates make openssh rsync openssl
ENV SSHD_CONFIG_FILEPATH /etc/ssh/sshd_config
ENV ROOK_SSH_AUTHKEYS_FILEPATH /root/.ssh/authorized_keys
ENV ROOK_SSH_PUBKEY_FILEPATH /conf/id_key.pub
ENV ROOK_SSH_SERVERKEYS_FILEPATH_LIST "/etc/ssh/ssh_host_ecdsa_key /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_ed25519_key"
COPY run.sh /run.sh
RUN chmod +x /run.sh
EXPOSE 22
ENTRYPOINT ["/run.sh"]
ここで実行している run.sh ファイルの内容は次のようになっています。
#!/bin/bash -x
## update /etc/ssh/sshd_config
SSHD_CONFIG_FILEPATH="${SSHD_CONFIG_FILEPATH:-/etc/ssh/sshd_config}"
ROOK_SSH_SERVERKEYS_FILEPATH_LIST="${ROOK_SSH_SERVERKEYS_FILEPATH_LIST:-/etc/ssh/ssh_host_rsa_key}"
for item in ${ROOK_SSH_SERVERKEYS_FILEPATH_LIST}
do
echo "HostKey ${item}" >> "${SSHD_CONFIG_FILEPATH}"
done
echo "PubkeyAuthentication yes" >> "${SSHD_CONFIG_FILEPATH}"
echo "PasswordAuthentication no" >> "${SSHD_CONFIG_FILEPATH}"
echo "PermitRootLogin yes" >> "${SSHD_CONFIG_FILEPATH}"
echo "StrictModes yes" >> "${SSHD_CONFIG_FILEPATH}"
## prepare the ~/.ssh/authorized_keys
ROOK_SSH_PUBKEY_FILEPATH="${ROOK_SSH_PUBKEY_FILEPATH:-/conf/id_key.pub}"
ROOK_SSH_AUTHKEYS_FILEPATH="${ROOK_SSH_AUTHKEYS_FILEPATH:-/root/.ssh/authorized_keys}"
ROOK_SSH_AUTHKEYS_BASEDIR="$(dirname ${ROOK_SSH_AUTHKEYS_FILEPATH})"
mkdir -p "${ROOK_SSH_AUTHKEYS_BASEDIR}"
chmod 700 "${ROOK_SSH_AUTHKEYS_BASEDIR}"
cp "${ROOK_SSH_PUBKEY_FILEPATH}" "${ROOK_SSH_AUTHKEYS_FILEPATH}"
chmod 400 "${ROOK_SSH_AUTHKEYS_FILEPATH}"
## randamize root password
echo "root:$(openssl rand -hex 12)" | chpasswd
exec /usr/sbin/sshd -D
この run.sh スクリプトは、あらかじめ外部で準備したSSHサーバー用の鍵ファイルを利用するように構成されていて、これだけでは起動しません。Ubuntu/CentOSなどに標準添付されている openssh-server の標準的な動作では、ランダムな鍵ファイルを生成しますが、ここでは生成されたファイルを配置することだけ行なっています。
Kuberntesでの設定
この openssh-ssh-server
をKubernetes上で動作させ、myfs-pvc
をマウントし、必要なファイルを転送します。
ここでの作業は適当な作業用ディレクトリを準備してから行なってください。
まず作業用ディレクトリ conf
を準備し、必要な設定ファイルを生成します。
$ mkdir conf
$ for key in rsa ecdsa ed25519 ; do test ! -f "ssh_host_${key}_key" && ssh-keygen -t "${key}" -f "conf/ssh_host_${key}_key"; done
$ ssh-keygen -t ed25519 -f conf/id_ed25519
ssh-keygenコマンドを実行すると、パスフレーズ(pass-phrase)を入力するよう促されますが、エンターキーを押してパスフレーズは設定しないでください。(no pass-phrase設定)
無事に生成すると、次のようなファイルが作成されているはずです。
$ ls conf/
id_ed25519 ssh_host_ecdsa_key.pub ssh_host_rsa_key
id_ed25519.pub ssh_host_ed25519_key ssh_host_rsa_key.pub
ssh_host_ecdsa_key ssh_host_ed25519_key.pub
次にkubectlコマンドを利用して、secretsオブジェクトを生成します。
$ kubectl -n $(id -un) create secret generic ssh-host-keys --from-file=conf/ssh_host_ecdsa_key --from-file=conf/ssh_host_ed25519_key --from-file=conf/ssh_host_rsa_key
$ kubectl -n $(id -un) create secret generic ssh-auhorized-keys --from-file=conf/id_ed25519.pub
鍵ファイルを再度登録したい場合には、一度Secretオブジェクトを削除してから再度作成してください。
$ kubectl -n $(id -un) delete secret ssh-host-keys
$ kubectl -n $(id -un) delete secret ssh-auhorized-keys
次はこの登録された情報を利用して、sccp-ssh-server
を起動します。
$ kubectl -n $(id -un) apply -f "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/tutorial-nginx-pvc/deploy-sccp-ssh-server.yaml"
続いてサービスを登録しますが、これは type: loadBalancer
を利用します。
$ kubectl -n $(id -un) apply -f "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/tutorial-nginx-pvc/svc-ssh-server.yaml"
ここまで無事に完了すると、SSHでアクセスするためのIPアドレスが割り当てられているはずです。
$ kubectl -n $(id -un) get svc openssh-server
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
openssh-server LoadBalancer 10.233.2.117 192.168.100.160 22:31068/TCP 4m22s
EXTERNAL-IP / 192.168.100.160
の部分は、各自で異なるので、自分のEXTERNAL-IPを確認してください。
ここで表示されるSSHサーバーを利用し、手元でindex.htmlファイルを作成し、転送してみます。
まず適当なindex.htmlファイルを準備します。
$ emacs index.html
内容は任意ですが、例えば、次のような内容にします。
<html>
<h1>Hello, guys!!</h1>
<p>abcdefg</p>
</html>
次にこのファイルを転送します。
$ scp -i conf/id_ed25519 index.html root@192.168.100.160:/data/index.html
転送したファイルが表示されるか確認してください。
Hugoを利用した静的コンテンツの生成
Webページを作成する際には、WordPressのようなCMSツールを利用するケースも一般的ですが、動的なアプリケーションである必要がないのであれば、静的コンテンツとして生成する方法がより安全といえます。
ここでは、Hugoを利用して静的コンテンツについて学びつつ、生成物をrsyncコマンドによって、PVCに転送し、nginxからそれなりの見栄えのWebページを作成してみます。
Hugoの利用について
作業用に適当なディレクトリを作成してから始めることをお勧めします。
まず始めることは、公式サイトのQuick StartのページのStep2から始めていきます。
公式ページの説明では、quickstart
のように名前をつけていますが、例えば、my-site
のように別名を指定することもできます。
$ hugo new site my-site
この時指定した、my-site
や quickstart
という名前のディレクトリが作成されます。
画面には次のようなメッセージが表示されます。
Congratulations! Your new Hugo site is created in ......../my-site.
Just a few more steps and you're ready to go:
1. Download a theme into the same-named folder.
Choose a theme from https://themes.gohugo.io/ or
create your own with the "hugo new theme <THEMENAME>" command.
2. Perhaps you want to add some content. You can add single files
with "hugo new <SECTIONNAME>/<FILENAME>.<FORMAT>".
3. Start the built-in live server via "hugo server".
このディレクトリに移動してから、操作を行なっていきます。
公式ガイドでは、`git init
などのコマンドを実行していますが、必須ではありません。
この操作では、テーマを配置しています。 公式サイトでは様々なHugo用のテーマが紹介されていますので、この他のテーマを利用することも可能です。
$ cd my-site
$ git clone https://github.com/theNewDynamic/gohugo-theme-ananke.git themes/ananke
具体的なコンテンツを作成します。 このため、hugoコマンドにコンテンツファイルを作成させます。
$ hugo new posts/my-first-post.md
次のようなメッセージが表示され、実際のファイルは、content/posts/my-first-post.md
に作成されていることが分かります。
/home/..../my-site/content/posts/my-first-post.md created
ここでは公式ガイドに手順はありませんが、作成した content/posts/my-first-post.md
ファイルを編集します。
emacs などで開き、次のように draft: false
を設定します。title/dateは変更する必要はありません。(変更しても構いません。)
---
title: "My First Post"
date: 2021-07-13T06:38:38Z
draft: false
---
emacsを閉じて、次に進みます。
公式ガイドでは、Step5でサーバーを立てて内容を確認しています。 実行前に、全てのhugoコマンドを強制的に停止させます。
$ sudo killall hugo
$ hugo server -D &
次のように画面に表示されるので、ポート番号を確認して、Webブラウザから同じ番号に接続してください。
Start building sites …
hugo v0.85.0+extended linux/amd64 BuildDate=unknown
WARN 2021/07/13 06:42:22 found no layout file for "HTML" for kind "page": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
| EN
-------------------+-----
Pages | 4
Paginator pages | 0
Non-page files | 0
Static files | 0
Processed images | 0
Aliases | 0
Sitemaps | 1
Cleaned | 0
Built in 31 ms
Watching for changes in /home/professor/yasu-abe/sccp/sccp2021_1H/20210713.hugo/my-site/{archetypes,content,data,layouts,static}
Watching for config changes in /home/professor/yasu-abe/sccp/sccp2021_1H/20210713.hugo/my-site/config.toml
Environment: "development"
Serving pages from memory
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop
$
Webブラウザから、http://localhost:1313/
に接続しますが、まだ画面はまっしろなままのはずです。
次に公式ガイドのStep6に進み、 config.toml ファイルを emacs などのエディタで開き、次のように編集します。 具体的には、先頭のURLを自分が使用するものに変更し、一番最後のテーマを指定する1行を追加します。
baseURL = "https://inovtst9.u-aizu.ac.jp/s12xxxxx/"
languageCode = "en-us"
title = "My New Hugo Site"
theme = "ananke"
s12xxxxx
の部分が自分のnamespace(AINS-ID)と同じになっていることを確認してください。
この編集が終ると、Webブラウザが再描画され、先ほど作成した My First Post
が画面に表示されるはずです。
ここまで確認したら、一度 hugo を停止します。
$ killall hugo
PVCへの転送
先ほど画面に表示したコンテンツを public ディレクトリに生成します。
$ rm -rf public
$ hugo
hugoコマンドをオプションなしに実行すると、public/ ディレクトリに、コンテンツを出力します。 画面には次のように表示されるはずです。
Start building sites …
hugo v0.85.0+extended linux/amd64 BuildDate=unknown
| EN
-------------------+-----
Pages | 7
Paginator pages | 0
Non-page files | 0
Static files | 1
Processed images | 0
Aliases | 0
Sitemaps | 1
Cleaned | 0
Total in 84 ms
このファイルの内容を、rsync を利用して、PVCに転送します。
まず自分の app/my-sshserver
のExternal-IPを確認しましょう。
kubectl -n $(id -un) get svc openssh-server -o wide
次のように表示されますので、自分の External-IP 192.168.100.xxx
を確認します。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
openssh-server LoadBalancer 10.233.2.117 192.168.100.160 22:31068/TCP 22h app=my-sshserver
この External-IP を利用して、次のようにrsyncコマンドを実行します。
ここで conf/id_ed25519
の部分は、自分が作成したファイルのパス(path)に置き換えてください。
$ rsync -av -e "ssh -i conf/id_ed25519" public/. root@192.168.100.160:/data/.
ファイルが転送されると、無事にコンテンツが表示されるはずです。
実際にHugoを利用したプロジェクトについて
このSCCPのWebページのディレクトリを以下のURLで公開しています。
以上