明日から本気だす

データベース好きなサポートエンジニアのメモです.

Minikube で kubernetes 入門してみた

はじめに

前々から気になっていた kubernetes を入門するため、まずはローカルの Minikube 環境でいろいろと触ってみたときのメモ。どこから手を付けるべきか迷ったので Udemy の 米シリコンバレーDevOpsエンジニア監修!超Kubernetes完全入門(2020)【優しい図解説とハンズオン】 をセール時に購入し、コースのハンズオンに沿って勉強した。すごいわかりやすいのでおすすめ。

Minikube とは

PC 上の VM 環境でシングルノードの Kubenetes クラスターを実行するためのツール。以下の環境にインストール。

  • Docker Desktop 3.1.0
  • WSL v2 Ubuntu 20.04

環境の構築

kubectl のインストール

まずは kubectl をインストールする。kubectlクラスターのエンドポイント(API Server)と SSL 通信してリソースなどを制御する。WSL2 上の Ubuntu で実行する。

$ curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl

Minikube のインストール

Minikube のインストール。同じく WSL2 上の Ubuntu で実行する。

$ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
$ sudo install minikube-linux-amd64 /usr/local/bin/minikube

起動と停止

起動

WSL2 上の Ubuntuminikube start を実行する。

$ /usr/local/bin/minikube start --vm-driver=docker
😄  minikube v1.17.0 on Ubuntu 20.04
✨  Using the docker driver based on existing profile
🎉  minikube 1.17.1 is available! Download it: https://github.com/kubernetes/minikube/releases/tag/v1.17.1
💡  To disable this notice, run: 'minikube config set WantUpdateNotification false'

👍  Starting control plane node minikube in cluster minikube
🔄  Restarting existing docker container for "minikube" ...
🐳  Preparing Kubernetes v1.20.2 on Docker 20.10.2 ...
🔎  Verifying Kubernetes components...
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

docker コマンドで確認すると minikube のコンテナが稼働してる。

$ docker ps -a
CONTAINER ID   IMAGE                                 COMMAND                  CREATED      STATUS                      PORTS     NAMES
37cb31974986   gcr.io/k8s-minikube/kicbase:v0.0.17   "/usr/local/bin/entr…"   7 days ago   Exited (130) 35 hours ago             minikube

停止

停止は minikube stop で OK。

$ minikube stop
✋  Stopping node "minikube"  ...
🛑  Powering off "minikube" via SSH ...
🛑  1 nodes stopped.

Pod

k8s では Pod という単位でコンテナを管理する。Pod は仮想 NIC や Volume が共有され、同一のノードに配置される。

Hello World Pod の起動

kubectlrun オプションで Pod を起動する。 --restart=Never を指定しないとデフォルトでは deployment が作成されてしまう。

$ kubectl run --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld

Pod の情報を確認

curl コマンドで Pod にアクセスする場合、Service が作成されていないので、curl イメージからのみアクセスが可能。

$ kubectl get pod,svc -o wide
# -- Pod 内のログを確認
$ kubectl describe pod helloworld 
# -- Pod のメタ情報を確認
$ kubectl logs helloworld

# -- pod の IP アドレスを確認
$ kubectl get pod -o wide | awk 'NR>1 {print $6}; END{sub(/[ \t]+$/, "")}'
# -- curl image からアクセス
$ kubectl run --restart Never --image curlimages/curl:7.68.0 -it --rm curl sh

Pod への接続

-it はコンテナの標準入力に擬似 tty を割り当てるオプション。

$ kubectl exec -it helloworld sh

Pod 削除

$ kubectl delete pod hellworld

Pod に環境変数を設定

docker コマンドと同じ。

$ kubectl run --env TEST_ENV=hello_world --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
# -- 確認方法
$ kubectl exec -it helloworld env

Service

永続的な IP アドレスを持たない Pod に対して、クライアントからのアクセスするためのオブジェクト。Pod 内外に公開するための L4 ロードバランサーの役割を担う。サービスのタイプは以下のとおり。

サービスタイプ 内容
ClusterIP Pod の前でスタティック IP をもったロードバランサーとして機能する。クラスター外からは接続不可。
NodePort Node に対して振られるので、クラスター外からも IPと指定 Port でアクセスすることができる。ポートは 3000 番台が割り当てられる。
LoadBalancer NodePort の前でロードバランサーとして動作し、クラスター外からも代表 IP アドレスと Port でアクセスができる。L4 のロードバランシングのみ。
ExternalName

ClusterIP

ClusterIP を helloworld Pod に作成したあとに別 Pod から curl で接続を確認する。kubectl expose--type のデフォルトは ClusterIP となるため、省略可。

$ kubectl expose pod helloworld --type ClusterIP --port 8080 --name helloworld-clusterip

# -- curl image の Pod から確認
$ kubectl run --restart Never --image curlimages/curl:latest -it --rm curl sh
$ curl helloworld-clusterip:8080

NodeIP

NodeIP を作成して接続を確認する。Windows WSL を利用しているので Minikube は Docker Desktop 上のコンテナとして動作している。外部からの接続は Minikube のコンテナから実施する。

$ kubectl expose pod helloworld --type NodePort --port 8080 --name helloworld-nodeport

# -- NodeIP と Port を調べる
$ minikube ip
$ kubectl get pod,service

# -- minikube コンテナから接続を確認
$ docker exec -it minikube bash
$ curl <ip>:<port>

LoadBalancer

LoadBalancer を作成して接続を確認する。接続方法は NodeIP と同様。

$ kubectl expose pod helloworld --type LoadBalancer --port 8080 --name helloworld-lb

Ingress

LoadBalancer だと L4 でのロードバランシングとなり、Service 毎に作成されるので非効率。 L7 のロードバランシングでクラスター内外に Pod を公開する場合は Ingress を作成する。クラスター外部からアクセスする場合は URL パスによる Service の切り替えができる。

Minikube で Ingress を作成するための準備

Minikube の場合、アドオンで Ingress を有効にすると、Ingress Pod が追加される。

$ minikube addons list
$ minikube addons enable ingress
🔎  Verifying ingress addon...
🌟  The 'ingress' addon is enabled

# -- namespace で kube-system を指定
$ kubectl get pod --namespace kube-system
NAME                                        READY   STATUS      RESTARTS   AGE
coredns-74ff55c5b-wb628                     1/1     Running     5          7d11h
etcd-minikube                               1/1     Running     5          7d11h
ingress-nginx-admission-create-cf4n8        0/1     Completed   0          42s
ingress-nginx-admission-patch-rt69n         0/1     Completed   0          42s
ingress-nginx-controller-558664778f-2sdl5   0/1     Running     0          42s
kube-apiserver-minikube                     1/1     Running     5          7d11h
kube-controller-manager-minikube            1/1     Running     5          7d11h
kube-proxy-95zns                            1/1     Running     5          7d11h
kube-scheduler-minikube                     1/1     Running     5          7d11h
storage-provisioner                         1/1     Running     10         7d11h

YAML ファイルを指定して作成

Ingress リソースの作成して接続を確認する。YAML ファイルの kind:Ingress を指定。metadata: name: を helloworld で作成した。その他の YAML ファイルの書き方はドキュメントを参照。

参考: Ingress リソース

$ kubectl apply -f ingress.yaml
$ kubectl get ingress
# -- 詳細表示
$ kubectl describe ingress helloworld

ReplicaSet

Pod の複製(レプリカ)数を管理する。Deployment と一緒に利用する。YAML ファイルの kind: で ReplicaSet を指定。

参考: ReplicaSet

$ kubectl apply -f replicaset.yaml
$ kubectl get replicaset

replicaset 数の変更。下記のコマンドだと 5 へ変更している。

$ kubectl scale --replicas=5 replicaset.apps/helloworld

Deployment

複数の Pod でクラスタを構成する。ReplicaSet が利用され Pod のスケールアップなどが可能。Pod を作成時のオプション --restart Never を省略すると Deployment が作成される。

$ kubectl run --image gcr.io/google-samples/hello-app:1.0 helloworld

もしくは、以下のコマンドで作成する。kubectl のバグ(?)のため、自分の環境だと kubectl create による作成が必要だった。

$ kubectl create deployment --image gcr.io/google-samples/hello-app:1.0 helloworld

Deployment に NodePort を作成して curl でアクセス。

$ kubectl expose deployment helloworld --type NodePort --port 8080 --name helloworld-nodeport

# -- minikube 
$ docker exec -it minikube bash
$ curl <IP>:<Port>

Deployment のイメージをバージョンアップし crul でアクセスすると、徐々に Pod が 2.0 になっていくのがわかる。

$ kubectl set image deploy/helloworld hello-app=gcr.io/google-samples/hello-app:2.0

# -- minikube 
$ docker exec -it minikube bash
$ for i in {1..30}; do  curl <IP>:<Port>; sleep 3; done

YAML の利用

kubectl コマンドでリソース作成時に --dry-run=client-o yamlYAML 形式でマニュフェスト・ファイルを出力できる。ここまで、リソース作成に kubectl コマンドを利用してきたが、実運用ではマニュフェスト・ファイルでコードとして管理するほうが一般的。

# -- helloworld Pod の設定を yaml ファイルで出力
$ kubectl run --image grc.io/google-samples/hello-app:1.0 --restart Never --dry-run=client -o yaml helloworld > pod_helloworld.yaml
# -- Deployment の設定を yaml ファイルで出力
$ kubectl create deployment --image gcr.io/google-samples/hello-app:1.0 helloworld --dry-run=client -o yaml > deployment_helloworld.yaml

以下は YAML ファイルで複数のコンテナを定義した Deployment を定義したサンプル。kubectl create deployment で作成した deployment_helloworld.yamlimage: busybox の部分を追加したもの。 replicas: 5 なので、コンテナ hello-appsleep を含む Pod が 5 つデプロイされる。

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: helloworld
  name: helloworld
spec:
  replicas: 5
  selector:
    matchLabels:
      app: helloworld
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: helloworld
    spec:
      containers:
      - command:
        - /bin/sh
        - -c
        - sleep 5000
        image: busybox
        name: sleep
        ports:
        - containerPort: 80
      - image: gcr.io/google-samples/hello-app:1.0
        name: hello-app
        ports:
        - containerPort: 8080
status: {}

YAML からリソース作成

上記の YAML ファイルからリソースを作成するには以下のコマンドを実行。

$ kubectl apply -f deployment_helloworld.yaml
# -- リソースを削除
$ kubectl delete -f deployment_helloworld.yaml

Deployment の helloworld Pod のコンテナに接続する場合は -c オプションでコンテナ名を指定。

$ kubectl exec -it helloworld-77597bdc79-5qh75 -c hello-app sh

Config Map

設定をキーと値のペアで保存するための API オブジェクト。下記では、環境変数 TEST_ENV=helloworld の設定を ConfigMap で作成。

$ kubectl create configmap my-config --from-literal=TEST_ENV=helloworld --dry-run=client -o yaml > configmap.yaml
$ kubectl apply -f configmap.yaml

# -- 確認方法
$ kubectl get configmap
$ kubectl describe configmap my-config

Pod の YMAL ファイルの configMapKeyRef で作成した ConfigMap を指定する。

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: helloworld
  name: helloworld
spec:
  containers:
  - env:
    - name: TEST_ENV
      valueFrom:
        configMapKeyRef:
          name: my-config
          key: TEST_ENV
    image: gcr.io/google-samples/hello-app:1.0
    name: helloworld
    ports:
    - containerPort: 8080
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Never
status: {}

Pod を作成し、環境変数を確認すると ConfigMap を介して設定されている。

$ kubectl apply -f helloworld.yaml
# -- 確認方法
$ kubectl exec -it helloworld env

ConfigMap の KeyValue を Pod の Volume としてマウントすることもできる。

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: helloworld
  name: helloworld
spec:
  containers:
  - image: gcr.io/google-samples/hello-app:1.0
    name: helloworld
    ports:
    - containerPort: 8080
    resources: {}
    volumeMounts:
    - name: my-config-volume
      mountPath: /my-config/TEST_ENV
  volumes:
    - name: my-config-volume
      configMap:
        name: my-config
        items:
        - key: TEST_ENV
          path: keys
status: {}

PVC(永続ボリューム要求)

DB のデータファイルなどはノードに Persistent Volume を作成し保存することで、Pod が削除されてもデータの永続化が可能。Pod が Persistent Volume を利用する場合は PVC(永続ボリューム要求)を行う。

マウントボリュームの作成

Minikube でマウントボリュームを作成。

$ minikube ssh
$ sudo mkdir /mnt/pvc && sudo chown docker:docker /mnt/pvc
$ touch /mnt/pvc/persistent.txt

PV の作成

以下の YAML ファイルで PV を作成。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv
spec:
  storageClassName: manual
  capacity:
    storage: 100M
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/pvc"

リソースの作成と確認

$ kubectl apply -f persistent_vol.yaml
# -- 確認方法
$ kubectl get pv

PVC(永続ボリューム要求)

以下の YAML ファイルで PVC を作成。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10M

同様にリソースの作成と確認

$ kubectl apply -f persistent_vol_claim.yaml
# -- 確認方法
$ kubectl get pvc

Pod で PV を利用

Pod の YAML ファイルの persistentVolumeClaim で作成した PVC リソースを指定。

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: helloworld-pvc
  name: helloworld-pvc
spec:
  containers:
  - image: gcr.io/google-samples/hello-app:1.0
    name: helloworld-pvc
    ports:
    - containerPort: 8080
    resources: {}
    volumeMounts:
    - name: my-pv
      mountPath: /mnt/pvc
  volumes:
    - name: my-pv
      persistentVolumeClaim:
        claimName: pvc

Pod の作成と確認。Pod が削除されても Minikube(ホスト)上の /mnt/pvc に hogehoge.txt は保持される。

$ kubectl exec -it helloworld-pvc sh
$ cd /mnt/pvc
$ echo "hogehoge" > hogehoge.txt

その他

Master API Server エンドポイントを表示。

$ kubectl cluster-info

クラスターエンドポイントと CA cert を表示

$ kubectl config view

すべてのリソースを表示。

$ kubectl get all -o wide

ToDo

Kubernetes クラスターの構築にチャレンジしたい。

API Gateway を利用して S3 にファイルをアップロードする

はじめに

API Gateway から Lambda を介さず S3 にファイルをアップロードした際の手順メモ。 設定後は curl コマンドで API Gateway のエンドポイントに対してファイルを PUT し、S3 のバケットにファイルがアップロードされたところまで確認。

S3 バケット作成

マネージメントコンソールの Amazon S3 より、API Gateway を介してファイルをアップロードするバケットを作成しておく。バケット「パブリック・アクセスをすべてブロック」 のまま。その他の設定も基本的にデフォルトで OK だった。

IAM ロール作成

マネージメントコンソールの IAM より API Gateway から S3 へのアクセスするためのロールを作成する。信頼されたエンティティの選択で AWS サービスの API Gateway を選択


ロール作成後に、該当ロールの インラインポリシーの追加 より、S3 バケットへの PUT を許可するポリシーを作成する。

作成した my-sample-20210218 バケットに PUT を許可する。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:Put*",
            "Resource": [
                "arn:aws:s3:::my-sample-20210218/*"
            ]
        }
    ]
}

信頼関係の「信頼されたエンティティ」が apigateway.amazonaws.com 以外となっている場合は 信頼関係の編集 からポリシードキュメントを変更する。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

API Gateway

REST API を作成

マネージメントコンソールの API Gateway より REST API を作成する。


新しいAPI を選択し、「エンドポイントタイプ」を リージョン にして API を作成

リソースの作成

API 作成後は「アクション」の「リソース作成」より、新しい子リソース {folder} を追加し、同様に {folder} の子リソースとして {item} を追加する。

メソッドの作成

「アクション」の「メソッド作成」より、リソース {folder}/{item}PUT メソッドを作成する。

項目 内容
結合タイプ AWSサービス
AWS リージョン ap-northeast-1
AWS サービス Simple Storage Service(S3)
HTTPメソッド PUT
アクションの種類 パス上書きの使用
パスの上書き {bucket}/{object}
実行ロール 作成した IAM ロールの ARN を指定
コンテンツの処理 パススルー


メソッド作成後に、「統合リクエスト」から URL パスパラメータを追加しパスのマッピングを設定する。

名前 マッピング
bucket method.request.path.folder
object method.request.path.item


「メソッドリクエスト」から 「API キーの必要性」 を true に変更する。IAM による認証を利用する場合は「許可」を AWS_IAM に変更する。

デプロイ

「アクション」より「API のデプロイ」を選択する。「デプロイされるステージ」は v1 を指定。デプロイすると REST API のエンドポイントが公開される。

API キーの作成

API キーの作成より、新しい API キーを作成する。

使用量の作成

同じく使用量プランを作成し、作成した使用量プランにデプロイした API のステージを追加する。


API キータブでは、「API キーを使用量プランに追加」より、作成した API キーを紐付ける。

動作確認

最後に curl コマンドで確認する。

  • -Hx-api-key で作成した API キーを指定。
  • 同じく -HContent-Typetext/csv を指定。指定しないと JSON 形式でアップロードされてしまう。
  • --upload-file で S3 にアップロードするファイルを指定。
  • -v もしくは --verbose で詳細表示。
$ curl -H "x-api-key: <作成した API キー>" -H 'Content-Type:text/csv' --upload-file test.csv https://<API Gateway のエンドポイント>/<作成したバケット>/<オブジェクト名> -v

レスポンスコードが 403Forbidden が返ってくる場合は、IAM ロールの信頼関係の設定が誤っていないか確認。