Overview
kubernetesを使って実際にアプリケーションを動かしてみる。
人によって、コンテナだったり、Functionと呼んでいたりと、なんかいろいろあるみたいだが
ここでは「アプリケーション」と呼んでおく。
DinD等もあるので、アプリケーションという呼び方が正しいかどうかは状況に依りそうだ。
Precondition
- kubernetes 環境ができあがっている
- dashborad へのアクセスができる
CentOS7 kubespray で kubernetes cluster を作る - その1-
から続けているひとは「後片付け」だけしなければそのまま使える。
Scope of work
- Application deploy (Nginx)
- 外部からのアクセス許可
- データ・設定を保存する Application の deploy
- 後片付け
How to Operation
1. Application deploy (Nginx)
Log in kube master
- login to kubernetes master host
$ ssh k8master01
Create deploy
- Deploy nginx image
- nginx の versionはお好みで。ver指定が無くともimage=nginx ぐらいはしないと起動しない
- サービスポートも80で起動するようにオプションを追加して起動。
$ kubectl run nginx --image=nginx --port=80
ちなみに nginx:1.13 みたいな形でVerを指定してイメージを取得することもできる。
このイメージはデフォルトで dockerhub と google cloud を見ているようだ。
Check deployment
デプロイ状況のチェック。
イメージサイズが小さいのですぐに起動するとは思うが
get pod で STATUS が Running となっていない場合は、動作していない事になる。
$ kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 1 1 1 1 12m
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-f846cb5bc-4nkb4 1/1 Running 0 12m
$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
default nginx-f846cb5bc-4nkb4 1/1 Running 0 12m
--- snip ----
Check deployment detail
$ kubectl describe pod nginx-f846cb5bc-4nkb4
Name: nginx-f846cb5bc-4nkb4
Namespace: default
Node: k8master02/192.168.240.175
Start Time: Thu, 01 Feb 2018 08:48:04 +0900
Labels: pod-template-hash=940276167
run=nginx
Annotations: <none>
Status: Running
IP: 10.233.126.193
Controlled By: ReplicaSet/nginx-f846cb5bc
Containers:
nginx:
Container ID: docker://1f55bf003409b9204a19c0089f651218ab6e03040174ba512a4a3d6d3a903503
Image: nginx:1.13
Image ID: docker-pullable://nginx@sha256:285b49d42c703fdf257d1e2422765c4ba9d3e37768d6ea83d7fe2043dad6e63d
Port: 80/TCP
State: Running
Started: Thu, 01 Feb 2018 08:48:06 +0900
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-2jsqt (ro)
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
Volumes:
default-token-2jsqt:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-2jsqt
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 13m default-scheduler Successfully assigned nginx-f846cb5bc-4nkb4 to k8master02
Normal SuccessfulMountVolume 13m kubelet, k8master02 MountVolume.SetUp succeeded for volume "default-token-2jsqt"
Normal Pulled 13m kubelet, k8master02 Container image "nginx:1.13" already present on machine
Normal Created 13m kubelet, k8master02 Created container
Check from dashboard
- Open web browser, then access dashboad URL
2. Expose nginx application by node ip
このままでは外部からアクセスができないので外部アクセスを可能にする。
kubernetes では service の追加(作成)という操作になる。
$ kubectl expose deploy nginx --port=80 --target-port=80
- 実行結果。
$ kubectl get service nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.233.4.37 <none> 80/TCP 6s
- nginxへのアクセス
$ curl http://10.233.4.37
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
このようにClusterIPが付与され、アクセスできるようになった。
ただし、あくまでこのアドレスは、kubernetesの中での通信用の為、外部からはアクセスできない。
とりあえず外部からアクセスするためには 2つの方法がある。
- kube proxy を使う
- NodePort を使う
kube proxy 利用
master で kube proxy を起動する。
例によって addressやaccept-hostsを書かないと
外部からのアクセスがauth failとなってしまう為、以下のオプションを付与する。
# kubectl proxy --address=0.0.0.0 --accept-hosts=".*"
Starting to serve on [::]:8001
これで kube proxy を起動したホストの 8001 ポートへアクセスすれば良いのだが、
これはAPIアクセスにすぎないのでURLを正しく指定する必要がある。
URLパスは以下のようになるので、 pod name を把握する必要がある。
http://:8001/api/v1/proxy/namespaces/default/pods//
以下のような場合、pod name は nginx-7587c6fdb6-4jvp7 となる。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-7587c6fdb6-4jvp7 1/1 Running 0 1
従って、URLも以下のようになる。
NodePort によるアクセス
kube proxyによるアクセスの場合、URLが非常に長く直感的にアクセスがしづらい。
従って、NodePortを使ってコンテナのサービスを名実ともに外に出してやるのに
最も簡単な方法がNordPort。
先ほどのExpose (Create service)に対して編集をかけてやるだけで良い。
$ kubectl edit service nginx
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
kind: Service
metadata:
creationTimestamp: 2018-02-02T22:34:59Z
labels:
run: nginx
name: nginx
namespace: default
resourceVersion: "140161"
selfLink: /api/v1/namespaces/default/services/nginx
uid: 4cf93e78-0869-11e8-82c7-000c296cb132
spec:
clusterIP: 10.233.4.37
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
run: nginx
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
このように edit で開いたファイルで ClusterIP を NodePort に変更してやる。
Linuxデフォルトであればviで開かれるはず。
$ kubectl get service nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx NodePort 10.233.4.37 <none> 80:31700/TCP 59m
このように 31700 番ポートでアクセスできるようになる。
欄外
ちなみにpod情報、serviceファイルを理解したり
設定ファイルとして書き出す為にYAMLやJSONで出力することもできる。
$ kubectl get pod nginx -o yaml
$ kubectl get services nginx -o yaml
3. データ・設定を保存する Application の deploy
続いて、データや設定を保存するためのApplicationをdeployしてみる。
よりデータや構造をわかりやすくするために今度は jenkins を例にやってみることにする。
Create deployment file for Jenkins
以下を参考にjenkinsのdeploymentファイルを作成する。
なお、jenkinsの deployには
こちらで既に解説されているが
どうも1.9では、 deploy で作る方が良いらしい。
従って、Deploy形式で作成することにする。
$ vi jenkins-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins-deployment
labels:
app: jenkins
spec:
replicas: 1
selector:
matchLabels:
app: jenkins
template:
metadata:
labels:
app: jenkins
spec:
volumes:
- name: jenkinsdata
hostPath:
path: /var/tmp/jenkins_home
containers:
- name: jenkins
image: jenkins
ports:
- containerPort: 8080
volumeMounts:
- mountPath: /var/jenkins_home
name: jenkinsdata
ちなみに1. - 2. も同じようにdeploymentファイルで作成する場合は
以下のようなYAMLになっている
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
先ほどのjenkins-deploymentがnginxと大きく異なるのは volumes の項。
hostPath: 以下が追加されている。
ここで /var/tmp/jenkins_home と記載されており作成されたPodは
Nodeの /var/tmp/jenkins_home を mountPathの /var/jenkins_home をマウントする。
これにより jenkins のインストールコンテンツがコンテナ外に置かれるため、
Podが死んでもデータが残るようになる。
なお、 /var/tmp/jenkins_home は必ず全てのノードで 777 で作成しておくこと。
「全ての」が鬼門。Replicaの数とノード数によっては運良く、777で作成されたノードで
deployが始まり、うまく起動することもあるが、そうなると今度はそのノードが死んだときに
他のノードへ移った時にdeploy失敗という切ない事態に陥る。
つまり全てのノードでこれが必要
node$ mkdir /var/tmp/jenkins_home
node$ sudo chmod 777 /var/tmp/jenkins_home
Deployment jenkins
先ほど作成された deploymentファイルを元にdeployを行う
$ kubectl create -f jenkins-deployment.yaml
Expose jenkins
- の項で述べたようなもの。
外部からのアクセスできるよう service を設定する。
こちらもYAMLの流し込み方式でやってみる。
apiVersion: v1
kind: Service
metadata:
name: jenkins-services
spec:
ports:
- nodePort: 30000
port: 80
protocol: TCP
targetPort: 8080
selector:
app: jenkins
type: NodePort
$ kubectl create -f jenkins-services.yaml
NodePortで作成しており、ポートを30000に指定している。
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins-services NodePort 10.233.8.39 <none> 80:30000/TCP 5s
これでノードのIP 30000 へアクセスするとJenkinsが見えるようになる。
データの共有
今回の項で jenkins のデータは Node の /var/tmp/jenkins_home にマウント
(コンテナの外)してある。
ただし、このデータはノード間では共有されない。
従って、ここで設定した情報は、ノードが動かない限りはpodを作り直しても復活するが
ノードが移ると見事に無くなってしまう。そして移動先のノードで設定をしたものは
移動先のノードに保存されるため、再び元のノードに戻ってきた際にはロールバックしたような状態になる。
やってみると面白いが、これでは実用性がまるで無いのでデータを外に出すときは
その外に出したデータをノード間でどうやって同期するか?と考える必要がある。
- せっかくセットアップしたのに・・・
- node01を落とす
- node03 で上がった jenkinsにログインすると・・・
やり直し・・・ orz
4. 後片付け
それぞれ service と deploy(pod)を削除して完了。
$ kubectl delete service nginx
$ kubectl delete deploy nginx
$ kubectl delete service jenkins-services
$ kubectl delete deploy jenkins-deployment
全てのノードでデータを削除
node$ rm -rfv /var/tmp/jenkins_home