Kubernetes勉強会第1回 〜Secrets、StatefulSet、DaemonSet、API server への接続方法〜

Kubernetes in Action

Kubernetes in Action

「Kubernetes in Action」を読んで学んだ結果を社内で共有しました。 その第1回の内容です。

Secrets

  • ConfigMapと同様、Key-Value のリストだが、パスワードや認証情報等の秘密情報を格納するためのリソース。
  • Container から Secret を使うには、"環境変数"、"Volume としてマウント"の二種類がある。この使い方はConfigMapと変わらない。
  • 3つ種類がある。使い分けは以下
    • docker-registry: 認証が必要なDocker registryを使うときに使用する
    • generic: secretをローカルファイル、ディレクトリ、literal valueから生成する場合
    • tls: ingressSSL certificateに使用する場合

環境変数から使う場合

apiVersion: v1
kind: Pod
metadata:
  name: fortune-env
spec:
  containers:
  - image: luksa/fortune:env
    name: html-generator
    env:
    - name: MY_PASSWORD_SECRET
      valueFrom:
        secretKeyRef: # configMapを環境変数に使う場合はここが`configMapKeyRef`になる
          name: my-secret
          key: password

volumeとしてmountする

apiVersion: v1
kind: Pod
metadata:
  name: fortune-https
spec:
  containers:
  - image: nginx:alpine
    name: web-server
    volumeMounts:
    - name: certs
      mountPath: /etc/nginx/certs/
  volumes:
  - name: certs
    secret:
      secretName: fortune-https
$ kc exec git-sync-demo-b9cb448f7-972rh ls /var/run/secrets/kubernetes.io/serviceaccount/
ca.crt
namespace
token
  • Secretがbase64なのは、バイナリデータも含めることができるように。
  • Secretのサイズ上限は1M
  • private dockerレジストリからimageをpullする時の認証をsecretに登録するためには
$ kubectl create secret docker-registry mydockerhubsecret \
  --docker-username=myusername --docker-password=mypassword \
  --docker-email=my.email@provider.com

のようにしてsecret genericではなくsecret docker-registryを指定する。 podには以下のように imagePullSecrets を指定

apiVersion: v1
kind: Pod
metadata:
  name: private-pod
spec:
  imagePullSecrets:
  - name: mydockerhubsecret
  containers:
  - image: username/private:tag
    name: main

API server への接続方法

まずkubectlは中でKubernetes API ServerへREST APIリクエストを送って、Kubernetesの操作をしています。 そのため、kubectl --v=8 get podsのように--v=8オプションをつけて実行すると、どのようなREST APIが送信されているかみることができます。

$ kubectl --v=8 get node
省略...
I0321 19:31:59.047070    9111 round_trippers.go:414] GET https://192.168.99.100:8443/api/v1/nodes
I0321 19:31:59.047079    9111 round_trippers.go:421] Request Headers:
I0321 19:31:59.047086    9111 round_trippers.go:424]     Accept: application/json
I0321 19:31:59.047093    9111 round_trippers.go:424]     User-Agent: kubectl/v1.8.4 (darwin/amd64) kubernetes/9befc2b
I0321 19:31:59.060898    9111 round_trippers.go:439] Response Status: 200 OK in 13 milliseconds
I0321 19:31:59.060920    9111 round_trippers.go:442] Response Headers:
I0321 19:31:59.060926    9111 round_trippers.go:445]     Content-Type: application/json
I0321 19:31:59.060932    9111 round_trippers.go:445]     Content-Length: 3171
I0321 19:31:59.060937    9111 round_trippers.go:445]     Date: Wed, 21 Mar 2018 10:31:58 GMT
I0321 19:31:59.061025    9111 request.go:836] Response Body: {"kind":"NodeList","apiVersion":"v1","metadata": 長いので省略

Kubernetesの各pod内のコンテナからもAPI Serverを利用することができます。 参考: https://kubernetes.io/docs/tasks/administer-cluster/access-cluster-api/#accessing-the-api-from-a-pod

kubectl run curl --image=tutum/curl -- tail -f /dev/null kc exec -it pod名 /bin/bash でpodにログインし、

# 以下でkubernetes APIのIPとPORTがわかる。
$ env | grep KUBERNETES_SERVICE
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT_HTTPS=443

# SSL証明書を指定
export CURL_CA_BUNDLE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
# token(認証情報)を設定
export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

curl -H "Authorization: Bearer $TOKEN" https://10.96.0.1:443/api/v1/namespaces/default/pods

# kubernetesというドメインでもアクセスできる
curl -H "Authorization: Bearer $TOKEN" https://kubernetes/api/v1/namespaces/default/pods
curl -H "Authorization: Bearer $TOKEN" https://kubernetes/api/v1/namespaces/default/services/git-sync-demo

token(認証情報)はpod外から以下でも取得できる

$ kubectl describe secret $(kubectl get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d '\t'

認証方式はいくつかある kubernetesの認証とアクセス制御を動かしてみる

認可に関してはRBAC(Roles-Based Access Control)という機能が担う。

Rubyのkubernetes API クライアントは https://github.com/abonas/kubeclient がある。

StatefulSets

https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/

ステートフルなアプリケーション(例えばDB等)をサポートするためのリソース。

  • 再作成されてもpod nameやhostnameは同じ名前で生成される。
    • pod名は {name}-NというformatでNは0から始まる。つまり{name}-0, {name}-1, {name}-2 ...というように生成される。
  • 作成されるときは、次の使われていないindexを使って作成される。
  • podが起動するときは小さいindexから順に起動される。
  • またpodが削除されるときは大きいindexから順に削除される。
  • 同じPersistentVolumeClaimsを使おうとする。
  • 削除されるときは使っていたPersistentVolumeClaimsは削除されない。

例:

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: kubia
spec:
  serviceName: kubia
  replicas: 2
  template:
    metadata:
      labels:
        app: kubia
    spec:
      containers:
      - name: kubia
        image: luksa/kubia-pet
        ports:
        - name: http
          containerPort: 8080
        volumeMounts:
        - name: data
          mountPath: /var/data
  volumeClaimTemplates: # このテンプレートを使ってPersistentVolumeClaimsが作成される
  - metadata:
      name: data
    spec:
      resources:
        requests:
          storage: 1Mi
      accessModes:
      - ReadWriteOnce

参考: https://scrapbox.io/blackawa/StatefulSet%E3%81%A3%E3%81%A6%E3%81%84%E3%81%A4%E4%BD%BF%E3%81%86%E3%81%AE%EF%BC%9FPersistentVolumes%E3%81%A7%E3%81%84%E3%81%84%E3%82%93%E3%81%98%E3%82%83%E3%81%AA%E3%81%84%E3%81%AE%EF%BC%9F

DaemonSet

https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/

全てのnode、もしくは特定のnodeに必ず1つのpodを動かしたい場合にはDaemonSetを使うとよい。 たとえば、以下のケースに使える。

  • Cluster storage daemon(例えばglusterdやceph)を動かす場合
  • nodeのメトリックス収集用のpodを動かしたい場合(例えば Prometheus Node Exporter, collectd, Datadog agent, New Relic agent, or Ganglia gmond.)
  • nodeのログを収集するpodを動かしたい場合(fluentd や logstash)
  • nodeのネットワークを操作するためのpodを動かしたい場合

例:

apiVersion: apps/v1beta2
kind: DaemonSet
metadata:
  name: ssd-monitor
spec:
  selector:
    matchLabels:
      app: ssd-monitor
  template:
    metadata:
      labels:
        app: ssd-monitor
    spec:
      nodeSelector:
        disk: ssd
      containers:
      - name: main
        image: luksa/ssd-monitor

11. Understanding Kubernetes internals

  • Kubernetes SystemコンポーネントだけがKubernetes API Serverと通信をする
  • Kubernetes API serverのみがetcdと通信をする。他のコンポーネントは直接etcdと通信しない。 クラスタの状態もAPI Serverと通して行われる
  • ectdには楽観ロックで操作するので一貫性がとれる。

11.4.3 Introducing the Container Network Interface

  • コンテナ間で簡単にネットワーク通信できるようにContainer Network Interface (CNI)というプロジェクトがスタートした。 KubernetesはいくつかのCNI pluginを使うことができる。
    • Calico
    • Flannel
    • Romana
    • Weave Net
    • And others

CNIはDaemonSetとして各Nodeにデプロイされる。

http://tech.uzabase.com/entry/2017/09/12/164756