Kubernetes勉強会第1回 〜Secrets、StatefulSet、DaemonSet、API server への接続方法〜
- 作者: Marko Luksa
- 出版社/メーカー: Manning Pubns Co
- 発売日: 2018/01/20
- メディア: ペーパーバック
- この商品を含むブログを見る
「Kubernetes in Action」を読んで学んだ結果を社内で共有しました。 その第1回の内容です。
Secrets
- ConfigMapと同様、Key-Value のリストだが、パスワードや認証情報等の秘密情報を格納するためのリソース。
- Container から Secret を使うには、"環境変数"、"Volume としてマウント"の二種類がある。この使い方はConfigMapと変わらない。
- 3つ種類がある。使い分けは以下
環境変数から使う場合
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
- Secretはメモリ内に読み込まれる、ファイルには書き出されない。(volumeとしてmountするときはtmpfsに書かれる)
- ただしectdに保存されるときは平文で保存される(https://kubernetes.io/docs/concepts/configuration/secret/)
- KubernetesのSecretは本当に安全か
- 「Kubernetes 1.7よりetcdを暗号化する機能が開発されました」とのこと
- KubernetesのSecretは本当に安全か
- By default, the default-token Secret is mounted into every container,
$ 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 ...というように生成される。
- pod名は
- 作成されるときは、次の使われていない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
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にデプロイされる。