概要
参考にしたハンズオン
https://www.nic.ad.jp/ja/materials/iw/2018/proceedings/h2/h2-takara-3.pdf
https://www.nic.ad.jp/ja/materials/iw/2018/proceedings/h2/h2-takara-4.pdf
Kubernetes とは
Kubernetes は Linux コンテナの操作を自動化するOSSです。「k8s」や「kube」とも呼ばれます。
日本では「クーバネテス」「クーベネティス」などと発音されます。
Kubernetes を使用すると、アプリケーションのデプロイ、スケーリングなどを自動化できます。つまり、Linux コンテナを実行しているホストをまとめてクラスタ化できます。
用語集
よく登場する用語をまとめておきます。
ここで全てを覚える必要はなく、ハンズオン中にわからない用語が出てきたらこちらをご参照ください。
Kubernetes を構成する要素
- ポッド(Pod)
ポッドは複数のコンテナから構成されます。ポッド単位でコンテナが起動・破棄されます。また、ポッドは一時的な存在であるため再起動はありません。各ポッドには一意の仮想NICが割り当てられます。また、同じポッド内のコンテナ同士はIPアドレスを共有し、localhost で通信できます。 - ノード(Node)
Dockerコンテナを実行するサーバのことです。複数のポッドを持ちます。 - マスターノード(Master Node)
各ノードの管理を行うノードのことです。 - クラスター(Cluster)
コンテナやネットワークの設定などをクラスタリングしたものです。 - ネームスペース(Namespace)
ネームスペースをつけてクラスターを仮想化できるものです。あらかじめ「default」「docker」「kube-public」などのネームスペースが用意されています。例えば、WEBサーバ群、DBサーバ群、などのような分け方が想定できます。 - コンテキスト(Context)
Kubernetes の環境を分けるための定義です。 クラスター、ネームスペース、ユーザーをグループ化したものです。 - サービス(Service)
ポッドに対してクラスタ外からアクセスするためにはサービスを定義する必要があります。サービスにはクラスタの代表となるIPを指定します。
上記を制御するために登場する要素
- コントローラー
ポッドを制御するためのオブジェクトです。コントローラーには様々な種類があり、特性によって使い分けます。 - デプロイメント(Deployment)
最も良く使われるコントローラーがデプロイメントです。良くあるWEBサーバなどの用途ではこちらを使います。ポッド数をスケールしたり、ロールバックをしたり、求められる基本的な動作をします。 - Service
サービスを定義します。 - ConfigMap
コンテナで使用される設定を定義します。 - Secret
コンテナで使用される秘匿情報を定義します。 - Volume
コンテナに割り当てるストレージを定義します。 - Job
ジョブを定義します。 - CronJob
定期的に実行されるジョブを定義します。
その他の用語
- マニフェスト
Kubernetes の構成を定義するための形式(yamlファイル)のことです。
Mac で Kubernetes を使うには
Mac で Kubernetes を使うには、以下の方法があります。
それぞれメリット・デメリットがあります。
- Docker for Mac の Kubernetes を使う
- 既に Docker for Mac がインストールされている場合は最速の方法です。
- Docker for Mac 自体が重いという話があり、パフォーマンスが懸念されます。
- また、Kubernetes の構成に限りがあるらしいです。
- Minikube を使う
- 自動で Vagrant の仮想環境をたて、Kubernetes を実行してくれます。
- より完全に近い Kubernetes 環境を再現してくれるらしいです。
Docker for Mac 版ハンズオン
概要
既に Docker for Mac がインストールされている方は、Docker for Mac の Kubernetes を使うのが早いです。
Kubernetes にはGUIでコンテナの状態を確認できるダッシュボード機能が備わっています。
視覚的に状態を確認しながら理解を進めていきましょう。
前提
- OSX が Docker for Mac 18.06 以上に対応していること
インストール
以下を参考に Docker for Mac をインストールします。
https://docs.docker.com/docker-for-mac/install/
Kubernetes を Enable にする
Docker のメニューを開き、「Preferences」を押下します。
表示された設定メニューの中から「Kubernetes」を選択すると以下のような画面になります。
「Enable Kubernetes」「Deploy Docker Stacks to Kubernetes by default」「Show system containers (advanced)」の3つをチェックし「Apply & Restart」をします。
メニューバーに「Kubenetes is running」という項目が出るので、しばらくして緑色になることを確認します。
続いてターミナルから Context を「docker-for-desktop」に切り替えます。
$ kubectl config use-context docker-for-desktop
Switched to context "docker-for-desktop".
コンテキストの状態を見てみます。
指定したコンテキストになっていることが確認できます。
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
docker-desktop docker-desktop docker-desktop
* docker-for-desktop docker-desktop docker-desktop
クラスター、コンテキストなどが今どういう状態になっているかは以下のコマンドを打つことによって確認できます。
$ kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://kubernetes.docker.internal:6443
name: docker-desktop
contexts:
- context:
cluster: docker-desktop
user: docker-desktop
name: docker-desktop
- context:
cluster: docker-desktop
user: docker-desktop
name: docker-for-desktop
current-context: docker-for-desktop
kind: Config
preferences: {}
users:
- name: docker-desktop
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
ご興味があれば、以下のようなコマンドで、Docker イメージの生成状況、コンテナが起動していること、Kubernetes の Pods が出来ていることも確認できます。
$ docker images
$ docker ps -a
$ kubectl get pods --all-namespaces
ダッシュボードを有効にする
ダッシュボードを有効にすると、上記コマンドで確認したような Kubernetes の状態をGUIで見ることができます。
ダッシュボードの詳細は以下を参照ください。
https://github.com/kubernetes/dashboard
まずは以下のコマンドでダッシュボードを有効にします。
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-rc6/aio/deploy/recommended.yaml
続いてダッシュボードを起動します。
$ kubectl proxy
Starting to serve on 127.0.0.1:8001
立ち上がったら以下のリンクからダッシュボードにアクセスしてみます。
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
すると認証画面が表示されます。
トークンが必要になるので、ターミナルからトークンを探します。
まず「default-token」から始まる secret を探し、さらにその詳細情報を確認します。するとトークンが表示されます。
$ kubectl -n kube-system get secret | grep default-token
default-token-h5snm kubernetes.io/service-account-token 3 3d22h
$ kubectl -n kube-system describe secret default-token-h5snm
Name: default-token-h5snm
Namespace: kube-system
Labels: <none>
Annotations: kubernetes.io/service-account.name: default
kubernetes.io/service-account.uid: 9e7e6f74-a435-4f90-83a1-cbca37953aa5
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1025 bytes
namespace: 11 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlc...
トークンを先ほどの認証画面に入力し、ログインします。
以下のような画面が表示されれば成功です。
Hello World を実行する
Kubernetes を構成するには通常マニフェストを記述しますが、最初は簡単に試してみたいので、Hello World を実行して様子を見てみます。
以下をコマンドを実行します。
$ kubectl run hello-world --image=hello-world -it --restart=Never
立ち上がったら、先ほどのダッシュボードから見てみます。
hello-world というポッドが1つ出来ていますね。「default」ネームスペースがついていて、ノードは1つしかないので「docker-desktop」を使っています。
クリックするとさらに詳細を見ることができます。
ターミナルから確認する場合は以下のコマンドで見れます。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
hello-world 0/1 Completed 0 15m
$ kubectl describe pod
Name: hello-world
Namespace: default
Priority: 0
Node: docker-desktop/192.168.65.3
Start Time: Mon, 30 Mar 2020 18:11:16 +0900
Labels: run=hello-world
Annotations: <none>
Status: Succeeded
IP: 10.1.0.12
...
なんとなくポッドとダッシュボードが見れたところで、このポッドは削除しておきます。
$ kubectl delete pod hello-world
マニフェストを記述する
では、次はマニフェストを記述してみましょう。
ここからはハンズオン用のリポジトリを使って確認していきます。
https://github.com/larable/grpc-go-handson-for-mac
以下のようにリポジトリをクローンしておきます。
git clone git@github.com:larable/grpc-go-handson-for-mac.git
マニフェストの基本的な要素は以下です。
apiVersion: v1 # APIのバージョン
kind: Pod # APIの種別
metadata:
name: test # オブジェクト名
spec: # オブジェクトの仕様
containers:
- name: ubuntu
image: ubuntu:18.04
これを理解した上で、デプロイメントのマニフェストを記述していきたいところですが、今回は先ほどのリポジトリの以下のマニフェストを使いましょう。
k8s/dev-bgg-deployment.yaml
こちらのマニフェストも先ほどの基本の構造をベースに記述されています。
新しく登場した項目にはコメントをつけてあります。
apiVersion: apps/v1
kind: Deployment
metadata:
name: bgg-deployment
spec:
replicas: 1 # レプリカ数
selector:
matchLabels:
app: backend
template: # ポッドを生成する際のテンプレート
metadata:
labels:
app: backend # デプロイメントのポッドと対応づける
spec:
containers:
- image: boilerplate-grpc-go
imagePullPolicy: IfNotPresent # ローカルになければ Docker Hub から pull する
securityContext:
capabilities:
add:
- SYS_PTRACE
name: bgg-container
env:
- name: GRPC_PORT
value: "50051"
ports:
- containerPort: 50051
- containerPort: 40000
readinessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
initialDelaySeconds: 1
timeoutSeconds: 1
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
initialDelaySeconds: 1
timeoutSeconds: 1
resources:
limits:
cpu: 100m
memory: 32Mi
requests:
cpu: 100m
memory: 32Mi
デプロイメントからポッドを起動する
上記のファイルからオブジェクトの生成をしてみます。
その前に、ローカルに Docker イメージが作成されていないとエラーになるので、起動しておきます。
$ # おまじない
$ export KUBECONTEXT=minikube
$ export IMAGE=boilerplate-grpc-go
$ sh build.sh
では起動してみます。
$ kubectl apply -f k8s/dev-bgg-deployment.yaml
deployment.apps/bgg-deployment created
デプロイメントとポッドの状態を確認してみます。
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
bgg-deployment 1/1 1 1 74s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
bgg-deployment-85449c8b86-w4ltj 1/1 Running 0 79s
立ち上がっていることが確認できました。
ちなみに、オブジェクトを削除したいときは以下のコマンドでできます。
$ kubectl delete -f k8s/dev-bgg-deployment.yaml
サービスを追加する
ポッドが起動しましたが、このままでは外部からアクセスできません。
アクセスするためにはサービスを追加する必要があります。
サービスとは、IPアドレスの定義、DNS定義、負荷分散などをしてくれるものです。
サービスもマニフェストで記述します。
では、サンプルリポジトリの以下のファイルを使って試してみましょう。
k8s/dev-bgg-service.yaml
apiVersion: v1
kind: Service
metadata:
name: bgg-headless-svc # 内部DNSへ登録する名前
spec:
clusterIP: None
ports:
- name: headless
port: 50051
protocol: TCP
targetPort: 50051
selector:
app: backend # デプロイメントのラベルを指定する
ではサービスを生成してみます。
$ kubectl apply -f k8s/dev-bgg-service.yaml
起動したサービスを見てみると、指定したポートで立ち上がっていることが確認できます。
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
bgg-headless-svc ClusterIP None <none> 50051/TCP 8m28s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8
この状態でダッシュボードを見てみましょう。
デプロイメント、ポッド、レプリカセットが生成されていることが確認できます。
ここまでで作ったものは一旦削除しておきます。
$ kubectl delete -f k8s/dev-bgg-service.yaml
service "bgg-headless-svc" deleted
$ kubectl delete -f k8s/dev-bgg-deployment.yaml
deployment.apps "bgg-deployment" deleted
skaffold の導入
これまでで kubernetes の基本動作はわかりました。
しかしローカル開発で頻繁に環境を更新している場面だと、docker イメージ作成 〜 k8s 起動 までの手順はやや煩雑です。
さらに、複数のサービスを立ち上げようと思うとより大変になります。
そこで登場するのが skaffold です。
skaffold は docker build 〜 kubectl apply までを手順化して簡単に実行できます。また、ファイルを監視し変更があった場合に自動で反映してくれる機能もあります。
まずはインストール
$ brew install skaffold
skaffold の設定は skaffold.yaml に記述します。
今回はサンプルリポジトリの skaffold.yaml を参考に試してみます。
apiVersion: skaffold/v2alpha4
kind: Config
build:
artifacts:
- image: boilerplate-grpc-go
custom:
buildCommand: ./build.sh
dependencies:
paths:
- main.go
- service
- go.mod
- go.sum
- build.sh
- Dockerfile
local:
useDockerCLI: true
useBuildkit: true
concurrency: 1
profiles:
- name: local
activation:
- kubeContext: minikube
build:
local:
push: false
deploy:
kubectl:
manifests:
- k8s/dev-*.yaml
- name: stg
activation:
- kubeContext: arn:aws:eks:us-west-2:113269943850:cluster/eks-sandbox
build:
artifacts:
- image: 113269943850.dkr.ecr.us-west-2.amazonaws.com/boilerplate/grpc-go
deploy:
kubectl:
manifests:
- k8s/stg-*.yaml
では起動してみます。
初回はしばらく時間がかかります。
$ kubectl config use-context minikube
$ skaffold dev
これで起動が確認できました。
skaffold dev
ではアプリケーションの変更を検知してビルド〜デプロイを実行しますが、一度のみ実行したい場合は以下のコマンドを実行します。
$ skaffold run
以上で完了です。
Minikube 版ハンズオン
余力があれば記載します。
トラブルシューティング
docker コマンド、kubectl コマンド の応答が返ってこない
docker コマンドや kubectl コマンドの応答が返って来ない場合や、タイムアウトと表示される場合は、docker desctop を再起動します。
メニューバーの docker から restart するか、それすらも固まっている場合はアクティビティモニタなどから再起動します。
kubectl apply でオブジェクトが生成されないときの調査方法
以下のコマンドでオブジェクトの詳細やログを確認し、原因を突き止めます。
$ # 詳細を確認
$ kubectl describe [オブジェクト名] [名前]
$ # ログを確認
$ kubectl logs [名前]
dockerイメージが見つからないエラーが出る
kubectl apply でローカルの docker イメージを使ってほしいのに、見つからないエラーが出る場合の対処方です。
-
image pull policy
をIfNotPresent (ローカルになければpull)
にする - docker イメージのタグを latest にしない