Kubernetesをいきなり始める場合、訳のわからない単語がいっぱい出てきて(単語自体の意味が分かってもその単語が何を意味しているかはわからないことが多い)、なかなか全体のイメージしにくい。まずシンプルな環境で理解しようとする。
単語
そうは言っても、幾つか基本単語の意味を少し把握しないと。
Kubernetes(k8s)は、ギリシャ語で航海長または水先案内人の意味である。
航海長または水先案内人として、仕事は何でしょう?
海運・港湾で大量のコンテナが行き来するから、それをさばけるよう水路を開けたり航路を指示したりして、
コンテナがうまく機能するよう、オーケストレーションする「システム」である。
詳細はWikipeidiaにあるの「Kubernetesのアーキテクチャ図」はわかりやすい。
Kubernetesのパッケージ管理ツールはhelm「舵」というツールである。
パッケージはchart「海図」という倉庫に保管される(githubと類似)。
Kubernetesの管理は、コマンドラインツールであるkubectlまたはweb画面のコンソールで行う。
幾つかわかりにくい点についての説明:
- Kubernetesは基本的にクラスタ内で閉ざされている世界となる。
- ポッドにクラスタ内のIPアドレスをランダムに割り当てて、ポッド再起動するとIPアドレスが変わる(かもしれない)。
- コンテナはIPアドレスを持たない。外部との通信にIPアドレスが必要とする場合、ポッドのIPアドレスを共用する(恐らく)。
- コンテナは提供する機能をサービスとしてポッド経由で公開できる。それでも、クラスタ内からのみ利用できる。
- サービスへのアクセスは、環境変数かクラスタDNSを用いてアクセスする。
→ 具体的などれかのポッド(IPアドレス)を指名してアクセスできない。 - サービスをIngressという仕組みでクラスタ外部へ公開できる。
Google Kubernetes Engine(GKT)を90日間300ドルクレジット付きで無料体験可能。
ただ、Kubernetesは複雑なため、その前に、ローカルで体験可能なminikubeで概念把握をしたほうがよい。
以下はUbuntu上でminikubeをセットアップしてみる方法を説明する。
Dockerのインストール
minikubeはDockerを利用してローカル上にminikubeという仮想マシン(コンテナ)を作成し、その中でkubernetesのクラスタを一つ構築する。
なので、先にDockerをインストールしておく。
ちなみに、仮想マシン作成できるのであれば、Dockerではなく、KVMやVirtualBoxなどのハイパーバイザーでもよい。
~$ sudo apt install docker.io
※ インストール後dockerコマンドを実行するたびにsudoが必要だが、これを省略する方法として、下記コマンドで現在ユーザxxxをdockerグループに追加してubuntu再起動。
~$ sudo gpasswd -a xxx docker
kubectlのインストール
minikube含め、kubernetesとのやり取りに使うコマンドツールである。先にインストールしておく。
~$ curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
~$ sudo chmod +x kubectl
~$ sudo mv kubectl /usr/local/bin/
minikubeのインストール
~$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
~$ sudo chmod +x minikube
~$ sudo mv minikube /usr/local/bin/
minikube起動
~$ minikube start
初回起動時は、k8s(minikube)のイメージ(preloaded-images-k8s-v6-v1.19.4-docker-overlay2-amd64.tar.lz4)をインターネットからpullするので、多少時間がかかる(500MiB弱)。
参考のため、以下その出力を示す:
~$ minikube start
😄 Ubuntu 20.04 上の minikube v1.15.1
✨ dockerドライバーが自動的に選択されました
👍 コントロールプレーンのノード minikube を minikube 上で起動しています
🚜 Pulling base image ...
💾 Kubernetes v1.19.4 のダウンロードの準備をしています
> preloaded-images-k8s-v6-v1.19.4-docker-overlay2-amd64.tar.lz4: 486.35 MiB
🔥 docker container (CPUs=2, Memory=2200MB) を作成しています...
🐳 Docker 19.03.13 で Kubernetes v1.19.4 を準備しています...
🔎 Kubernetes コンポーネントを検証しています...
🌟 有効なアドオン: storage-provisioner, default-storageclass
🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
デフォルトでは2cpuと2Gのメモリのクラスタを一つ作成する。これではactiviti7のデプロイメントに足りないので、後で再作成が必要。
そう、最終目標はactiviti7
をローカルで構築したいので、これは別話。
- 状態確認
~$ minikube stats
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
- kubectlで確認
~$ kubectl version
Client Version: version.Info{Major:"1", Minor:"19", GitVersion:"v1.19.4", GitCommit:"d360454c9bcd1634cf4cc52d1867af5491dc9c5f", GitTreeState:"clean", BuildDate:"2020-11-11T13:17:17Z", GoVersion:"go1.15.2", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"19", GitVersion:"v1.19.4", GitCommit:"d360454c9bcd1634cf4cc52d1867af5491dc9c5f", GitTreeState:"clean", BuildDate:"2020-11-11T13:09:17Z", GoVersion:"go1.15.2", Compiler:"gc", Platform:"linux/amd64"}
ここでのServer Version
というのが、kubernetesクラスタのこと。
minikube start
は、実際にminikubeというコンテナを作成して、その中にControl Plane一式(マスター)が実行している。
- dockerでminikubeの実体を確認してみる:
~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
18ac3ceb3c43 gcr.io/k8s-minikube/kicbase:v0.0.14 "/usr/local/bin/entr…" 12 minutes ago Up 12 minutes 127.0.0.1:32771->22/tcp, 127.0.0.1:32770->2376/tcp, 127.0.0.1:32769->5000/tcp, 127.0.0.1:32768->8443/tcp minikube
- dockerのネットワークを確認してみる:
~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
fa92b9cbeb63 bridge bridge local
ef4235778ea4 host host local
94102e388ff6 minikube bridge local
78575dd74c91 none null local
docker標準以外、minikube
というI/Fも作成されていることがわかる。
- 更に、ホスト(ubuntu)上のネットワークを確認すると
~$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:6b:7e:b6 brd ff:ff:ff:ff:ff:ff
inet 192.168.241.130/24 brd 192.168.241.255 scope global dynamic noprefixroute ens33
valid_lft 1489sec preferred_lft 1489sec
inet6 fe80::867c:e538:c0a6:4e9e/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:aa:49:53:39 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:aaff:fe49:5339/64 scope link
valid_lft forever preferred_lft forever
5: br-94102e388ff6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:d9:15:92:83 brd ff:ff:ff:ff:ff:ff
inet 192.168.49.1/24 brd 192.168.49.255 scope global br-94102e388ff6
valid_lft forever preferred_lft forever
inet6 fe80::42:d9ff:fe15:9283/64 scope link
valid_lft forever preferred_lft forever
11: veth1696d8c@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-94102e388ff6 state UP group default
link/ether 4e:bc:ef:46:b9:3a brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::4cbc:efff:fe46:b93a/64 scope link
valid_lft forever preferred_lft forever
192.168.49.1/24
のI/Fはminikubeが作ったもので、minikubeコンテナ(クラスタ)自身は192.168.49.2
となる。
docker ps
で表示したとおり、minikube内ポート22、2376、5000、8443が開いている。ローカルでsshも接続できるが、minikubeコマンドでも入ることは可能。
~$ minikube ssh
プロンプトはdocker@minikube:~$
になり、dockerというユーザでminikube内に入っていることがわかる。
docker@minikube:~$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:35:84:79:d0 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
4: veth031a7c0@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether a6:0b:0a:46:1e:59 brd ff:ff:ff:ff:ff:ff link-netnsid 1
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c0:a8:31:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.49.2/24 brd 192.168.49.255 scope global eth0
valid_lft forever preferred_lft forever
ついでに、minikube内実行しているものを確認している:
docker@minikube:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2913795687ac 86262685d9ab "/metrics-sidecar" 9 minutes ago Up 9 minutes k8s_dashboard-metrics-scraper_dashboard-metrics-scraper-c95fcf479-tcrxh_kubernetes-dashboard_abc990db-b76d-4b49-a132-e9075f2b5284_0
dcff4352dfe1 503bc4b7440b "/dashboard --insecu…" 9 minutes ago Up 9 minutes k8s_kubernetes-dashboard_kubernetes-dashboard-584f46694c-bln68_kubernetes-dashboard_17c76048-19ad-4b31-a265-65e6eaf11930_0
3b38a2626b9c k8s.gcr.io/pause:3.2 "/pause" 9 minutes ago Up 9 minutes k8s_POD_dashboard-metrics-scraper-c95fcf479-tcrxh_kubernetes-dashboard_abc990db-b76d-4b49-a132-e9075f2b5284_0
5fc085cffc88 k8s.gcr.io/pause:3.2 "/pause" 9 minutes ago Up 9 minutes k8s_POD_kubernetes-dashboard-584f46694c-bln68_kubernetes-dashboard_17c76048-19ad-4b31-a265-65e6eaf11930_0
c5c25ae72949 bad58561c4be "/storage-provisioner" 32 minutes ago Up 32 minutes k8s_storage-provisioner_storage-provisioner_kube-system_e293829b-88c0-4945-96d3-da9b4cf315cd_1
01331ea01bff bfe3a36ebd25 "/coredns -conf /etc…" 33 minutes ago Up 33 minutes k8s_coredns_coredns-f9fd979d6-d8dxz_kube-system_a8874625-18e0-4519-afcb-8de29785de20_0
b8bbe6dda1b6 635b36f4d89f "/usr/local/bin/kube…" 33 minutes ago Up 33 minutes k8s_kube-proxy_kube-proxy-bqbxx_kube-system_236b6d80-b0d6-4bec-85d9-e4743a1e02c7_0
2ca9dba74db4 k8s.gcr.io/pause:3.2 "/pause" 33 minutes ago Up 33 minutes k8s_POD_storage-provisioner_kube-system_e293829b-88c0-4945-96d3-da9b4cf315cd_0
d6250bd16083 k8s.gcr.io/pause:3.2 "/pause" 33 minutes ago Up 33 minutes k8s_POD_kube-proxy-bqbxx_kube-system_236b6d80-b0d6-4bec-85d9-e4743a1e02c7_0
4da275c3e1ca k8s.gcr.io/pause:3.2 "/pause" 33 minutes ago Up 33 minutes k8s_POD_coredns-f9fd979d6-d8dxz_kube-system_a8874625-18e0-4519-afcb-8de29785de20_0
dce47e24c1b0 14cd22f7abe7 "kube-scheduler --au…" 34 minutes ago Up 34 minutes k8s_kube-scheduler_kube-scheduler-minikube_kube-system_38744c90661b22e9ae232b0452c54538_0
c935d124f5ec 4830ab618586 "kube-controller-man…" 34 minutes ago Up 34 minutes k8s_kube-controller-manager_kube-controller-manager-minikube_kube-system_627d9013c9c4b1cbfb72b4c0ef6cd100_0
3313416b54e3 0369cf4303ff "etcd --advertise-cl…" 34 minutes ago Up 34 minutes k8s_etcd_etcd-minikube_kube-system_d186e6390814d4dd7e770f47c08e98a2_0
f62f32307740 b15c6247777d "kube-apiserver --ad…" 34 minutes ago Up 34 minutes k8s_kube-apiserver_kube-apiserver-minikube_kube-system_e30eb1a2f7c2dbcda239c972918b3eb4_0
e5fb4bcabab3 k8s.gcr.io/pause:3.2 "/pause" 34 minutes ago Up 34 minutes k8s_POD_kube-scheduler-minikube_kube-system_38744c90661b22e9ae232b0452c54538_0
2cd92b6687d0 k8s.gcr.io/pause:3.2 "/pause" 34 minutes ago Up 34 minutes k8s_POD_kube-controller-manager-minikube_kube-system_627d9013c9c4b1cbfb72b4c0ef6cd100_0
2a8784961b87 k8s.gcr.io/pause:3.2 "/pause" 34 minutes ago Up 34 minutes k8s_POD_kube-apiserver-minikube_kube-system_e30eb1a2f7c2dbcda239c972918b3eb4_0
e20d541cffa9 k8s.gcr.io/pause:3.2 "/pause" 34 minutes ago Up 34 minutes k8s_POD_etcd-minikube_kube-system_d186e6390814d4dd7e770f47c08e98a2_0
kubernetesのコンポーネント一式(api-server
、scheduler
、controller-manager
など)もコンテナ方式で実行されていることがわかる。
Dashboardでクラスタを覗いてみる
Dashboardはkubernetesの機能であり、addonで実装している。addonをenableでもよいし、以下のコマンドで自動的にdashboard有効化とブラウザ表示ができる。
~$ minikube dashboard &
🔌 ダッシュボードを有効化しています...
🤔 ダッシュボードの状態を確認しています...
🚀 プロキシを起動しています...
🤔 プロキシの状態を確認しています...
🎉 Opening http://127.0.0.1:37457/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ in your default browser...
webアプリデプロイ
簡単なサンプルwebアプリをデプロイして、クラスタ外部(ホスト)からアクセスできるようにやってみる。
- echoserverをデプロイする
~$ kubectl create deployment hello-minikube --image=k8s.gcr.io/echoserver:1.10
deployment.apps/hello-minikube created
echoserverはhello-minikubeというIDでクラスタにデプロイメントされる。
→ クラスタは適切なノードに適切な数のポッドを作成し、その中にコンテナを作成してくれる。
- 確認してみる:
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
hello-minikube-5d9b964bfb-hlcbp 1/1 Running 0 14m
hello-minikube-5d9b964bfb-hlcbp
というポッドが実行してくれてる。
- hello-minikubeにアクセス可能にする
~$ kubectl expose deployment hello-minikube --type=NodePort --port=8080
service/hello-minikube exposed
→ type=NodePortという方法でポッドの8080ポートに公開した。
- サービスの公開状況を確認
~$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-minikube NodePort 10.101.171.101 <none> 8080:30985/TCP 10m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 59m
10.101.171.101
はhello-minikube-5d9b964bfb-hlcbp
ポッドのIPのようだが、どうやってアクセス?
~$ minikube service hello-minikube --url
http://192.168.49.2:30985
つまり、上記URLにマッピングしていること。192.168.49.2の30985にアクセスすれば、クラスタがhello-minikube-5d9b964bfb-hlcbpポッドの8080番へ転送してくれる。
ブラウザで確認してよいし、curlで確認してみる:
~$ curl http://192.168.49.2:30985
Hostname: hello-minikube-5d9b964bfb-hlcbp
Pod Information:
-no pod information available-
Server values:
server_version=nginx: 1.13.3 - lua: 10008
Request Information:
client_address=172.17.0.1
method=GET
real path=/
query=
request_version=1.1
request_scheme=http
request_uri=http://192.168.49.2:8080/
Request Headers:
accept=*/*
host=192.168.49.2:30985
user-agent=curl/7.68.0
Request Body:
-no body in request-
上記client_address=172.17.0.1に注目したい。このIPはminikube内のdocker0というI/Fに割り当てている。
つまり、通信は192.168.49.1(ubuntu)->192.168.49.2(minikube)->172.17.0.1(minikube内のdocker)->10.101.171.101のような流れ。
「kubectl expose」でサービスを公開するときに作成する外部ポートはランダムなため、これをクラスタ外部から利用しにくい。
これの解決方法はingress controler
(入り口制御)という仕組み。適切にルーティングしてくれる。
- ingress controler有効化
~$ minikube addons enable ingress
🔎 Verifying ingress addon...
🌟 The 'ingress' addon is enabled
- 以下のingressリソース用yamlファイル(例:example-ingress.yaml)を作成する
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: example-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: 192.168.49.2.nip.io
http:
paths:
- path: /
backend:
serviceName: hello-minikube
servicePort: 8080
hostの192.168.49.2.nip.ioはhostsファイル編集しなくても使えるdnsサービスnip.ioを活用したい。
このファイルはminikubeの外部IP192.168.49.2に対してhttpつまり80番ポートに対してリクエストが来ると、そのURLはhttp://192.168.49.2.nip.io
のルートであれば、「hello-minikube」というサービスの8080番へルーティングする、という意味である。
- このファイルを適用
~$ kubectl apply -f example-ingress.yaml
Warning: networking.k8s.io/v1beta1 Ingress is deprecated in v1.19+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
ingress.networking.k8s.io/example-ingress created
警告はとりあえず無視。
- ingressリソース作成したか確認
~$ kubectl get ingress
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
example-ingress <none> 192.168.49.2.nip.ip 192.168.49.2 80 49s
良さそう。確認してみる。
~$ curl http://192.168.49.2.nip.io
Hostname: hello-minikube-5d9b964bfb-hlcbp
Pod Information:
-no pod information available-
Server values:
server_version=nginx: 1.13.3 - lua: 10008
Request Information:
client_address=172.17.0.6
method=GET
real path=/
query=
request_version=1.1
request_scheme=http
request_uri=http://192.168.49.2.nip.io:8080/
Request Headers:
accept=*/*
host=192.168.49.2.nip.io
user-agent=curl/7.68.0
x-forwarded-for=192.168.49.1
x-forwarded-host=192.168.49.2.nip.io
x-forwarded-port=80
x-forwarded-proto=http
x-real-ip=192.168.49.1
x-request-id=7cb265038c1206b47b32d0b613c41638
x-scheme=http
Request Body:
-no body in request-
いい感じでござる。
minikubeの停止
~$ minikube stop
✋ ノード "minikube" を停止しています...
🛑 SSH 経由で「minikube」の電源をオフにしています...
🛑 1台のノードが停止しました。
クラスタが停止しただけなので、次回startすれば、上記addonやデプロイ、ingressなど、全て復元できる。
minikubeの削除
~$ minikube delete
これは、minikubeというコンテナを削除するため、次回startは初期状態の新しいコンテナが作成されることになる。
minikubeのイメージはローカルに残されているため、インターネットから再ダウンロード不要。再作成は速い。
以上、とりあえずminikubeを構築し、簡単なwebアプリもminikubeの外からアクセスできるところまで来た。
めでたしめでたし。