元ネタは下記です。
https://github.com/kelseyhightower/kubernetes-the-hard-way
翻訳しつつ、いろいろなネタをはさんで紹介できればと思います。
Kubernetes Hard Wayでは、Kubernetesの設定を一から進めます。
なので、このラボは、完全に自動化されて管理されたKubernetesクラスタ作るコマンドを探している人のためのものではありません。
このKubernetes The Hard Wayは学習することに最適化されています。
Kubernetesクラスタを立ち上げるための必要な各タスクを確実に理解するための、長い道のりが示されています。
本番用のKubernetesクラスタをサポートすることを計画していて、かつ、Kubenretesクラスタのすべての部品がどのように組み合わさっているかを理解したいという人向けです。
Kubernetes The Hard Wayでは、コンポーネント間のエンドツーエンドの暗号化とRBAC認証ができる、可用性の高いKubernetesクラスタを作ります。
使うコンポーネントとそのバージョン一覧は下記の通りです
このラボでは、Google Cloud Platformを使うことを前提にしています。
GCPはインフラのベースで使いますが、このラボで学んだ内容は他のプラットフォームにも適用できます。
では、はじめていきましょう!
今回はGCPを使うので、サインアップをお願いします。
初回には$300の無料枠があります。
大体のコストは$0.22 / hour ($5.39 / day)くらいです。
このドキュメント を参考にgcloud
コマンドの準備をしてください。
最初に gcloud
コマンドを使う場合は init を使うのが一番手っ取り早いです。
% gcloud init
もしくは、自前でGCEのデフォルトのリージョンの設定していきましょう
% gcloud config set compute/region us-west1 % gcloud config set compute/zone us-west1-c
ちなみに自分は、サービスに影響ありそうなので、設定せずにリージョンを指定して叩くようにしました。
一応おすすめ設定として書かれているので興味がある人は下記を見てみてください。
cfssl
と cfssljson
はPKIの環境構築とTLSの証明書発行に使います。
Linuxの手順もありますが、今回はMacのみ記載します。
brew install cfssl
Linuxの手順はこちらから
https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/02-client-tools.md#linux
cfssl
のバージョンが1.2.0以上かどうか確認してください
# 手元のバージョン % cfssl version Version: 1.3.2 Revision: dev Runtime: go1.10
kubectl
のバージョンは1.12.0以上が必要です。
brew経由でもgcloud経由でインストールでもいいと思います。
今回はgcloudコマンド経由でインストールされる kubectl.1.12
コマンドを使おうと思います。
ここからKubernetesクラスタを作っていきます。
Kubernetesには、Kubernetesのコントロールプレーンとコンテナを動かくワーカーノードをホストするためのマシンが必要となります。
このステップでは、単一のゾーンでセキュアかつ可用性の高いKubernetesクラスタを動かすために必要なリソースをプロビジョニングします。
Kubernetesのネットワークモデルは、コンテナとノードが互いに通信できるフラットなネットワークを想定しています。
このポリシーに沿えない場合は、Kubernetesのネットワークポリシーを使って、コンテナ群がお互いに通信したり、外部ネットワークと通信する方法を制限することが可能です。
KubernetesクラスターをホストするVPCの設定を行います。
まずは kubernetes-
the-hard-way という名前でVPCを作ります。
gcloud compute networks create kubernetes-the-hard-way --subnet-mode custom
VPCのサブネットは、Kubernetesクラスタの各ノードにプライベートIPアドレスを割り振るのに十分なIPアドレス範囲を確保する必要があります。
gcloud compute networks subnets create kubernetes \ --network kubernetes-the-hard-way \ --range 10.240.0.0/24
全てのプロトコルの内部通信を許可するようにFirewallの設定を行います。
gcloud compute firewall-rules create kubernetes-the-hard-way-allow-internal \ --allow tcp,udp,icmp \ --network kubernetes-the-hard-way \ --source-ranges 10.240.0.0/24,10.200.0.0/16
さらに、外部からのSSH、ICMP、HTTPSも許可するようにします
gcloud compute firewall-rules create kubernetes-the-hard-way-allow-external \ --allow tcp:22,tcp:6443,icmp \ --network kubernetes-the-hard-way \ --source-ranges 0.0.0.0/0
終わったら kubernetes-the-hard-way
VPCのネットワークの設定を確認してみましょう。
gcloud compute firewall-rules list --filter="network:kubernetes-the-hard-way"
例
NAME NETWORK DIRECTION PRIORITY ALLOW DENY kubernetes-the-hard-way-allow-external kubernetes-the-hard-way INGRESS 1000 tcp:22,tcp:6443,icmp kubernetes-the-hard-way-allow-internal kubernetes-the-hard-way INGRESS 1000 tcp,udp,icmp
KubernetesのAPIサーバーの前段の外部LBに付与するIPアドレスを払い出しましょう。
gcloud compute addresses create kubernetes-the-hard-way \ --region $(gcloud config get-value compute/region)
終わったら確認して見ましょう
gcloud compute addresses list --filter="name=('kubernetes-the-hard-way')"
例
NAME REGION ADDRESS STATUS kubernetes-the-hard-way us-west1 XX.XXX.XXX.XX RESERVED
このラボのGCEインスタンスは、containerdのコンテナランタイムをサポートしているUbuntu Server 18.04を使用してプロビジョニングします。
各GCEインスタンスには、Kubernetesのブートストラップのプロセスを簡単にするために固定のプライベートIPアドレスを割り振ります。
Kunernetesのコントロールプレーンを司るインスタンスを3つ立てます。
for i in 0 1 2; do gcloud compute instances create controller-${i} \ --async \ --boot-disk-size 200GB \ --can-ip-forward \ --image-family ubuntu-1804-lts \ --image-project ubuntu-os-cloud \ --machine-type n1-standard-1 \ --private-network-ip 10.240.0.1${i} \ --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \ --subnet kubernetes \ --tags kubernetes-the-hard-way,controller done
各ワーカーインスタンスには、KubernetesクラスタのCIDR範囲からPodに対するサブネットの割り当てが必要です。
Podのサブネットの割り当ては、後のステップでコンテナネットワークを設定するために使います。
pod-cidr
インスタンスメタデータは、実行時にPodのサブネット割り当てをインスタンスと共有するため(公開?)に使用されます。
Kubernetesのワーカーノードとして3つのインスタンスを作ります。
for i in 0 1 2; do gcloud compute instances create worker-${i} \ --async \ --boot-disk-size 200GB \ --can-ip-forward \ --image-family ubuntu-1804-lts \ --image-project ubuntu-os-cloud \ --machine-type n1-standard-1 \ --metadata pod-cidr=10.200.${i}.0/24 \ --private-network-ip 10.240.0.2${i} \ --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \ --subnet kubernetes \ --tags kubernetes-the-hard-way,worker done
終わったら確認してみましょう。
gcloud compute instances list
例
NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS controller-0 us-west1-c n1-standard-1 10.240.0.10 XX.XXX.XXX.XXX RUNNING controller-1 us-west1-c n1-standard-1 10.240.0.11 XX.XXX.X.XX RUNNING controller-2 us-west1-c n1-standard-1 10.240.0.12 XX.XXX.XXX.XX RUNNING worker-0 us-west1-c n1-standard-1 10.240.0.20 XXX.XXX.XXX.XX RUNNING worker-1 us-west1-c n1-standard-1 10.240.0.21 XX.XXX.XX.XXX RUNNING worker-2 us-west1-c n1-standard-1 10.240.0.22 XXX.XXX.XX.XX RUNNING
SSH経由でコントローラーとワーカーのインスタンスを設定します。
初めてインスタンスに接続するときに、インスタンスへの接続のドキュメントにある通り、SSHキーが自動的に生成されプロジェクトまたはインスタンスのメタデータに保存されます。
試しに controller-0
のインスタンスにアクセスしてみましょう。
gcloud compute ssh controller-0
初回のアクセス時にSSHの鍵が生成されます。
パスフレーズをプロンプト経由で入力してください。
WARNING: The public SSH key file for gcloud does not exist. WARNING: The private SSH key file for gcloud does not exist. WARNING: You do not have an SSH key for gcloud. WARNING: SSH keygen will be executed to generate a key. Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again:
このタイミングでSSHの鍵が生成されて、プロジェクトにアップロードされ保存されます。
Your identification has been saved in /home/$USER/.ssh/google_compute_engine. Your public key has been saved in /home/$USER/.ssh/google_compute_engine.pub. The key fingerprint is: SHA256:nz1i8jHmgQuGt+WscqP5SeIaSy5wyIJeL71MuV+QruE $USER@$HOSTNAME The key's randomart image is: +---[RSA 2048]----+ | | | | | | | . | |o. oS | |=... .o .o o | |+.+ =+=.+.X o | |.+ ==O*B.B = . | | .+.=EB++ o | +----[SHA256]-----+ Updating project ssh metadata...-Updated [https://www.googleapis.com/compute/v1/projects/$PROJECT_ID]. Updating project ssh metadata...done. Waiting for SSH key to propagate.
SSHの鍵のアプロードが完了すれば、controller-0
のインスタンスに入ることができます。
Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.15.0-1006-gcp x86_64) ... Last login: Sun May 13 14:34:27 2018 from XX.XXX.XXX.XX
ここまでできたら、インスタンスからexitしておきましょう。
このラボでは、CloudFlareのPKIツールキットである cfssl を使ってPKI基盤をプロビジョニングします。
そして、PKI基盤を利用して認証局を作り、etcd、kube-apiserver、kube-controller-manager、kube-scheduler、 kubelet、kube-proxyのコンポーネントのTLS証明書を生成します。
このステップでは、TLS証明書を生成するための認証局(CA)をプロビジョニングします。
まずは、CA設定ファイル、証明書、および秘密鍵を生成します。
{ cat > ca-config.json <<EOF { "signing": { "default": { "expiry": "8760h" }, "profiles": { "kubernetes": { "usages": ["signing", "key encipherment", "server auth", "client auth"], "expiry": "8760h" } } } } EOF cat > ca-csr.json <<EOF { "CN": "Kubernetes", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "Portland", "O": "Kubernetes", "OU": "CA", "ST": "Oregon" } ] } EOF cfssl gencert -initca ca-csr.json | cfssljson -bare ca }
生成物
ca-key.pem ca.pem
このステップでは、各Kubernetesコンポーネントで使うクライアント証明書とサーバー証明書、Kubernetes admin
ユーザー用のクライアント証明書を発行します。
まずは、 admin
用のクライアント証明書と秘密鍵を生成します。
{ cat > admin-csr.json <<EOF { "CN": "admin", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "Portland", "O": "system:masters", "OU": "Kubernetes The Hard Way", "ST": "Oregon" } ] } EOF cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca-config.json \ -profile=kubernetes \ admin-csr.json | cfssljson -bare admin }
生成物
admin-key.pem admin.pem
Kubernetesは、Node Authorizerと呼ばれる特別な用途向けの認可モードを利用します。
これは特にKubeletからのAPIリクエストの認証を行います。
Node Authorizerの認可のためには、Kubeletは、system:nodes
groupの中の system:node:<nodeName>
というユーザー名で認証されるように証明書を作成しなければなりません。
このステップでは、KubernetesワーカーノードごとにNode Authorizerの要求を満たす証明書と秘密鍵を発行します。
for instance in worker-0 worker-1 worker-2; do cat > ${instance}-csr.json <<EOF { "CN": "system:node:${instance}", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "Portland", "O": "system:nodes", "OU": "Kubernetes The Hard Way", "ST": "Oregon" } ] } EOF EXTERNAL_IP=$(gcloud compute instances describe ${instance} \ --format 'value(networkInterfaces[0].accessConfigs[0].natIP)') INTERNAL_IP=$(gcloud compute instances describe ${instance} \ --format 'value(networkInterfaces[0].networkIP)') cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca-config.json \ -hostname=${instance},${EXTERNAL_IP},${INTERNAL_IP} \ -profile=kubernetes \ ${instance}-csr.json | cfssljson -bare ${instance} done
生成物
worker-0-key.pem worker-0.pem worker-1-key.pem worker-1.pem worker-2-key.pem worker-2.pem
kube-controller-manager
クライアントの証明書と秘密鍵を発行します。
{ cat > kube-controller-manager-csr.json <<EOF { "CN": "system:kube-controller-manager", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "Portland", "O": "system:kube-controller-manager", "OU": "Kubernetes The Hard Way", "ST": "Oregon" } ] } EOF cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca-config.json \ -profile=kubernetes \ kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager }
生成物
kube-controller-manager-key.pem kube-controller-manager.pem
kube-proxy
クライアント用に証明書と秘密鍵を発行します。
{ cat > kube-proxy-csr.json <<EOF { "CN": "system:kube-proxy", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "Portland", "O": "system:node-proxier", "OU": "Kubernetes The Hard Way", "ST": "Oregon" } ] } EOF cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca-config.json \ -profile=kubernetes \ kube-proxy-csr.json | cfssljson -bare kube-proxy }
生成物
kube-proxy-key.pem kube-proxy.pem
kube-scheduler
クライアント用の証明書と秘密鍵を発行します。
{ cat > kube-scheduler-csr.json <<EOF { "CN": "system:kube-scheduler", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "Portland", "O": "system:kube-scheduler", "OU": "Kubernetes The Hard Way", "ST": "Oregon" } ] } EOF cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca-config.json \ -profile=kubernetes \ kube-scheduler-csr.json | cfssljson -bare kube-scheduler }
生成物
kube-scheduler-key.pem kube-scheduler.pem
kubernetes-the-hard-way
のstatic IPアドレスは、Kubernetes API サーバーの証明書のSAN(サブジェクトの別名)のリストに含める必要があります。
これにより、外部のクライアントでも証明書を使った検証を行います。
Kubernetes API サーバーの証明書と秘密鍵を生成します。
{ KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \ --region $(gcloud config get-value compute/region) \ --format 'value(address)') cat > kubernetes-csr.json <<EOF { "CN": "kubernetes", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "Portland", "O": "Kubernetes", "OU": "Kubernetes The Hard Way", "ST": "Oregon" } ] } EOF cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca-config.json \ -hostname=10.32.0.1,10.240.0.10,10.240.0.11,10.240.0.12,${KUBERNETES_PUBLIC_ADDRESS},127.0.0.1,kubernetes.default \ -profile=kubernetes \ kubernetes-csr.json | cfssljson -bare kubernetes }
生成物
kubernetes-key.pem kubernetes.pem
サービスアカウントの管理のドキュメントにあるように、Kubernetes Controller Managerは、サービスアカウントのトークンの生成と署名をするためにキーペアが必要になります。
service-account
の証明書と秘密鍵を発行します。
{ cat > service-account-csr.json <<EOF { "CN": "service-accounts", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "Portland", "O": "Kubernetes", "OU": "Kubernetes The Hard Way", "ST": "Oregon" } ] } EOF cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca-config.json \ -profile=kubernetes \ service-account-csr.json | cfssljson -bare service-account }
生成物
service-account-key.pem service-account.pem
証明書と秘密鍵を各ワーカーインスタンスに置きます。
for instance in worker-0 worker-1 worker-2; do gcloud compute scp ca.pem ${instance}-key.pem ${instance}.pem ${instance}:~/ done
コントローラーインスタンスにも証明書と秘密鍵も置きます。
for instance in controller-0 controller-1 controller-2; do gcloud compute scp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \ service-account-key.pem service-account.pem ${instance}:~/ done
ふーーー、やっとKubernetesぽくなってきたかな、、
このステップでは、Kubernetes APIサーバーがKubernetesのクライアントを認証できるようにするためのkubeconfigs(Kubernetes構成ファイル)を生成します。
まずは、conttoller-manager
、kubelet
、kube-proxy
、scheduler
、 admin
ユーザー用のkubeconfigファイルを生成します。
kubeconfigは、Kubernetes APIサーバーと接続するために必要です。
高可用性をサポートするために、Kubernetes APIサーバーの前段にある外部ロードバランサーに割り当てるためにこのIPアドレスを使います。
kubernetes-the-hard-way
のstatic IPアドレスを探して設定します。
KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \ --region $(gcloud config get-value compute/region) \ --format 'value(address)')
kubelet用のkubeconfigファイルを生成するときは、kubeletのノード名と同じクライアント証明書を使用する必要があります。
そうすると、kubeletがKubernetesのNode Authorizerによって認可されるようになります。
ワーカーノード毎にkubeconfigを生成します。
for instance in worker-0 worker-1 worker-2; do kubectl config set-cluster kubernetes-the-hard-way \ --certificate-authority=ca.pem \ --embed-certs=true \ --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 \ --kubeconfig=${instance}.kubeconfig kubectl config set-credentials system:node:${instance} \ --client-certificate=${instance}.pem \ --client-key=${instance}-key.pem \ --embed-certs=true \ --kubeconfig=${instance}.kubeconfig kubectl config set-context default \ --cluster=kubernetes-the-hard-way \ --user=system:node:${instance} \ --kubeconfig=${instance}.kubeconfig kubectl config use-context default --kubeconfig=${instance}.kubeconfig done
生成物
worker-0.kubeconfig worker-1.kubeconfig worker-2.kubeconfig
kube-proxy
のkubeconfigも生成します。
{ kubectl config set-cluster kubernetes-the-hard-way \ --certificate-authority=ca.pem \ --embed-certs=true \ --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 \ --kubeconfig=kube-proxy.kubeconfig kubectl config set-credentials system:kube-proxy \ --client-certificate=kube-proxy.pem \ --client-key=kube-proxy-key.pem \ --embed-certs=true \ --kubeconfig=kube-proxy.kubeconfig kubectl config set-context default \ --cluster=kubernetes-the-hard-way \ --user=system:kube-proxy \ --kubeconfig=kube-proxy.kubeconfig kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig }
生成物
kube-proxy.kubeconfig
ここまでくると、わかってきますね。
kube-controller-manager
のkubeconfigを生成します。
{ kubectl config set-cluster kubernetes-the-hard-way \ --certificate-authority=ca.pem \ --embed-certs=true \ --server=https://127.0.0.1:6443 \ --kubeconfig=kube-controller-manager.kubeconfig kubectl config set-credentials system:kube-controller-manager \ --client-certificate=kube-controller-manager.pem \ --client-key=kube-controller-manager-key.pem \ --embed-certs=true \ --kubeconfig=kube-controller-manager.kubeconfig kubectl config set-context default \ --cluster=kubernetes-the-hard-way \ --user=system:kube-controller-manager \ --kubeconfig=kube-controller-manager.kubeconfig kubectl config use-context default --kubeconfig=kube-controller-manager.kubeconfig }
生成物
kube-controller-manager.kubeconfig
kube-scheduler
のkubeconfigを生成します。
{ kubectl config set-cluster kubernetes-the-hard-way \ --certificate-authority=ca.pem \ --embed-certs=true \ --server=https://127.0.0.1:6443 \ --kubeconfig=kube-scheduler.kubeconfig kubectl config set-credentials system:kube-scheduler \ --client-certificate=kube-scheduler.pem \ --client-key=kube-scheduler-key.pem \ --embed-certs=true \ --kubeconfig=kube-scheduler.kubeconfig kubectl config set-context default \ --cluster=kubernetes-the-hard-way \ --user=system:kube-scheduler \ --kubeconfig=kube-scheduler.kubeconfig kubectl config use-context default --kubeconfig=kube-scheduler.kubeconfig }
生成物
kube-scheduler.kubeconfig
admin
ユーザーのkubeconfigを生成します。
{ kubectl config set-cluster kubernetes-the-hard-way \ --certificate-authority=ca.pem \ --embed-certs=true \ --server=https://127.0.0.1:6443 \ --kubeconfig=admin.kubeconfig kubectl config set-credentials admin \ --client-certificate=admin.pem \ --client-key=admin-key.pem \ --embed-certs=true \ --kubeconfig=admin.kubeconfig kubectl config set-context default \ --cluster=kubernetes-the-hard-way \ --user=admin \ --kubeconfig=admin.kubeconfig kubectl config use-context default --kubeconfig=admin.kubeconfig }
生成物
admin.kubeconfig
kubelet
とkube-proxy
のkubecnofigは各ワーカーノードにコピーします
for instance in worker-0 worker-1 worker-2; do gcloud compute scp ${instance}.kubeconfig kube-proxy.kubeconfig ${instance}:~/ done
kube-controller-manager
とkube-scheduler
のkubeconfigは各コントローラーインスタンスにコピーします。
for instance in controller-0 controller-1 controller-2; do gcloud compute scp admin.kubeconfig kube-controller-manager.kubeconfig kube-scheduler.kubeconfig ${instance}:~/ done
Kubernetesは、クラスタの状態、アプリケーションの設定、秘匿情報などを含むさまざまなデータが格納されます。
Kubernetesは、クラスタ内で保持しているデータを暗号化する機能が提供されています。
このステップでは、Kubernetes Secretsの暗号化に合わせた暗号化鍵と暗号化の設定を生成します。
暗号化鍵を生成します。
ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)
暗号化の設定のためのencryption-config.yaml
を生成します。(やっとkubenretesマニフェストがでてきたんじゃないか?)
cat > encryption-config.yaml <<EOF kind: EncryptionConfig apiVersion: v1 resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: ${ENCRYPTION_KEY} - identity: {} EOF
このencryption-config.yaml
を各コントローラーインスタンスにコピーします。
for instance in controller-0 controller-1 controller-2; do gcloud compute scp encryption-config.yaml ${instance}:~/ done
Kubernetesの各コンポーネントはステートレスになっており、クラスタの状態etcdに格納され管理されています。(つまりetcdが超重要)
このステップでは、3ノードのetcdクラスタを構築して、高可用性と安全な外部アクセスに対応します。
このステップのコマンドは、controller-0
、controller-1
、controller-2
の各コントローラインスタンスで実行する必要があります。
gcloudコマンド経由で各コントローラーインスタンスにログインをしてください。
gcloud compute ssh controller-0
tmuxを使えば、同時に複数のインスタンスにコマンド実行ができます。
こっちをみてみてね。
ここからの手順は各コントローラーインスタンスで行います。
etcdのバイナリをgithubからDLします。
wget -q --show-progress --https-only --timestamping \ "https://github.com/coreos/etcd/releases/download/v3.3.9/etcd-v3.3.9-linux-amd64.tar.gz"
DLしたファイルを展開してetcd
サーバーと etcdctl
コマンドラインユーティリティを取り出します。
{ tar -xvf etcd-v3.3.9-linux-amd64.tar.gz sudo mv etcd-v3.3.9-linux-amd64/etcd* /usr/local/bin/ }
{ sudo mkdir -p /etc/etcd /var/lib/etcd sudo cp ca.pem kubernetes-key.pem kubernetes.pem /etc/etcd/ }
インスタンスの内部IPアドレスは、クライアントのリクエストを受け付けて、etcdクラスタ間で通信するために使います。
現在のGCEインスタンスの内部IPアドレスを取得します。
INTERNAL_IP=$(curl -s -H "Metadata-Flavor: Google" \ http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip)
各etcdのメンバーは、etcdクラスター内で名前はユニークにする必要があります。
現在のGCEインスタンスのホスト名でetcdの名前を設定します。
ETCD_NAME=$(hostname -s)
etcd.service
としてsystemdのユニットファイルを作成します。
cat <<EOF | sudo tee /etc/systemd/system/etcd.service [Unit] Description=etcd Documentation=https://github.com/coreos [Service] ExecStart=/usr/local/bin/etcd \\ --name ${ETCD_NAME} \\ --cert-file=/etc/etcd/kubernetes.pem \\ --key-file=/etc/etcd/kubernetes-key.pem \\ --peer-cert-file=/etc/etcd/kubernetes.pem \\ --peer-key-file=/etc/etcd/kubernetes-key.pem \\ --trusted-ca-file=/etc/etcd/ca.pem \\ --peer-trusted-ca-file=/etc/etcd/ca.pem \\ --peer-client-cert-auth \\ --client-cert-auth \\ --initial-advertise-peer-urls https://${INTERNAL_IP}:2380 \\ --listen-peer-urls https://${INTERNAL_IP}:2380 \\ --listen-client-urls https://${INTERNAL_IP}:2379,https://127.0.0.1:2379 \\ --advertise-client-urls https://${INTERNAL_IP}:2379 \\ --initial-cluster-token etcd-cluster-0 \\ --initial-cluster controller-0=https://10.240.0.10:2380,controller-1=https://10.240.0.11:2380,controller-2=https://10.240.0.12:2380 \\ --initial-cluster-state new \\ --data-dir=/var/lib/etcd Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF
{ sudo systemctl daemon-reload sudo systemctl enable etcd sudo systemctl start etcd }
etcdのクラスタの確認しておきます。
sudo ETCDCTL_API=3 etcdctl member list \ --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/etcd/ca.pem \ --cert=/etc/etcd/kubernetes.pem \ --key=/etc/etcd/kubernetes-key.pem
例
3a57933972cb5131, started, controller-2, https://10.240.0.12:2380, https://10.240.0.12:2379 f98dc20bce6225a0, started, controller-0, https://10.240.0.10:2380, https://10.240.0.10:2379 ffed16798470cab5, started, controller-1, https://10.240.0.11:2380, https://10.240.0.11:2379
このステップでは、3つのコンピューティングインスタンスを使って可用性の高いKubernetesコントロールプレーンを作ります。
合わせて、Kubernetes API Serverを外部クライアントに公開する外部ロードバランサーも作成します。
各ノードに、Kubernetes API Server、Scheduler、およびController Managerのコンポーネントをインストールします。
前のステップと同じくこのステップでも、controller-0
、controller-1
、controller-2
の各コントローラインスタンスで実行する必要があります。
gcloudコマンド経由で各コントローラーインスタンスにログインをしてください。
gcloud compute ssh controller-0
tmuxを使えば、同時に複数のインスタンスにコマンド実行ができます。
こっちをみてみてね。
Kubernetesの設定をおくディレクトリを作成します。
sudo mkdir -p /etc/kubernetes/config
Kubernetesの公式のリリースバイナリをDLします
wget -q --show-progress --https-only --timestamping \ "https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kube-apiserver" \ "https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kube-controller-manager" \ "https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kube-scheduler" \ "https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubectl"
DLしたバイナリをインストールします。
{ chmod +x kube-apiserver kube-controller-manager kube-scheduler kubectl sudo mv kube-apiserver kube-controller-manager kube-scheduler kubectl /usr/local/bin/ }
{ sudo mkdir -p /var/lib/kubernetes/ sudo mv ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \ service-account-key.pem service-account.pem \ encryption-config.yaml /var/lib/kubernetes/ }
APIサーバーをクラスターのメンバーに知らせるための設定として、インスタンスの内部IPアドレスを使います。
現在のGCEインスタンスの内部IPアドレスを取得します。
INTERNAL_IP=$(curl -s -H "Metadata-Flavor: Google" \ http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip)
kube-apiserver.service
のsystemdのユニットファイルを生成します。
cat <<EOF | sudo tee /etc/systemd/system/kube-apiserver.service [Unit] Description=Kubernetes API Server Documentation=https://github.com/kubernetes/kubernetes [Service] ExecStart=/usr/local/bin/kube-apiserver \\ --advertise-address=${INTERNAL_IP} \\ --allow-privileged=true \\ --apiserver-count=3 \\ --audit-log-maxage=30 \\ --audit-log-maxbackup=3 \\ --audit-log-maxsize=100 \\ --audit-log-path=/var/log/audit.log \\ --authorization-mode=Node,RBAC \\ --bind-address=0.0.0.0 \\ --client-ca-file=/var/lib/kubernetes/ca.pem \\ --enable-admission-plugins=Initializers,NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \\ --enable-swagger-ui=true \\ --etcd-cafile=/var/lib/kubernetes/ca.pem \\ --etcd-certfile=/var/lib/kubernetes/kubernetes.pem \\ --etcd-keyfile=/var/lib/kubernetes/kubernetes-key.pem \\ --etcd-servers=https://10.240.0.10:2379,https://10.240.0.11:2379,https://10.240.0.12:2379 \\ --event-ttl=1h \\ --experimental-encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \\ --kubelet-certificate-authority=/var/lib/kubernetes/ca.pem \\ --kubelet-client-certificate=/var/lib/kubernetes/kubernetes.pem \\ --kubelet-client-key=/var/lib/kubernetes/kubernetes-key.pem \\ --kubelet-https=true \\ --runtime-config=api/all \\ --service-account-key-file=/var/lib/kubernetes/service-account.pem \\ --service-cluster-ip-range=10.32.0.0/24 \\ --service-node-port-range=30000-32767 \\ --tls-cert-file=/var/lib/kubernetes/kubernetes.pem \\ --tls-private-key-file=/var/lib/kubernetes/kubernetes-key.pem \\ --v=2 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF
参考 : https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/
kube-controller-manager
のkubeconfigを移動させます。
sudo mv kube-controller-manager.kubeconfig /var/lib/kubernetes/
kube-controller-manager.service
のsystemdユニットファイルを生成します。
cat <<EOF | sudo tee /etc/systemd/system/kube-controller-manager.service [Unit] Description=Kubernetes Controller Manager Documentation=https://github.com/kubernetes/kubernetes [Service] ExecStart=/usr/local/bin/kube-controller-manager \\ --address=0.0.0.0 \\ --cluster-cidr=10.200.0.0/16 \\ --cluster-name=kubernetes \\ --cluster-signing-cert-file=/var/lib/kubernetes/ca.pem \\ --cluster-signing-key-file=/var/lib/kubernetes/ca-key.pem \\ --kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \\ --leader-elect=true \\ --root-ca-file=/var/lib/kubernetes/ca.pem \\ --service-account-private-key-file=/var/lib/kubernetes/service-account-key.pem \\ --service-cluster-ip-range=10.32.0.0/24 \\ --use-service-account-credentials=true \\ --v=2 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF
kube-scheduler
のkubeconfigを移動させます。
sudo mv kube-scheduler.kubeconfig /var/lib/kubernetes/
kube-scheduler.yaml
を作ります。
cat <<EOF | sudo tee /etc/kubernetes/config/kube-scheduler.yaml apiVersion: componentconfig/v1alpha1 kind: KubeSchedulerConfiguration clientConnection: kubeconfig: "/var/lib/kubernetes/kube-scheduler.kubeconfig" leaderElection: leaderElect: true EOF
kube-scheduler.service
のsystemdユニットファイルを生成します。
cat <<EOF | sudo tee /etc/systemd/system/kube-scheduler.service [Unit] Description=Kubernetes Scheduler Documentation=https://github.com/kubernetes/kubernetes [Service] ExecStart=/usr/local/bin/kube-scheduler \\ --config=/etc/kubernetes/config/kube-scheduler.yaml \\ --v=2 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF
コントローラーサービス群の起動
{ sudo systemctl daemon-reload sudo systemctl enable kube-apiserver kube-controller-manager kube-scheduler sudo systemctl start kube-apiserver kube-controller-manager kube-scheduler }
GCLBを使って3つのKubernetesAPIサーバーにトラフィックを分散させ、TSL接続をできるようにします。
GCLBはHTTPヘルスチェックのみをサポートしており、APIサーバーによって公開されているHTTPSエンドポイントはつかえません。
回避する方法として、nginx Webサーバーを使用してHTTPヘルスチェックのりクスエストをプロキシさせます。
このステップでは、nginxは80番ポートでHTTPヘルスチェックのリクエストをうけて、https://127.0.0.1:6443/healthz
のKubernetesAPIサーバーへプロキシするようにします。
HTTPヘルスチェックをハンドリングするためにnginxをインストールして起動します。
sudo apt-get install -y nginx
cat > kubernetes.default.svc.cluster.local <<EOF server { listen 80; server_name kubernetes.default.svc.cluster.local; location /healthz { proxy_pass https://127.0.0.1:6443/healthz; proxy_ssl_trusted_certificate /var/lib/kubernetes/ca.pem; } } EOF
{ sudo mv kubernetes.default.svc.cluster.local \ /etc/nginx/sites-available/kubernetes.default.svc.cluster.local sudo ln -s /etc/nginx/sites-available/kubernetes.default.svc.cluster.local /etc/nginx/sites-enabled/ }
sudo systemctl restart nginx sudo systemctl enable nginx
kubectl get componentstatuses --kubeconfig admin.kubeconfig
NAME STATUS MESSAGE ERROR controller-manager Healthy ok scheduler Healthy ok etcd-2 Healthy {"health": "true"} etcd-0 Healthy {"health": "true"} etcd-1 Healthy {"health": "true"}
nginxのHTTPヘルスチェックproxyのチェック
curl -H "Host: kubernetes.default.svc.cluster.local" -i http://127.0.0.1/healthz
HTTP/1.1 200 OK Server: nginx/1.14.0 (Ubuntu) Date: Sun, 30 Sep 2018 17:44:24 GMT Content-Type: text/plain; charset=utf-8 Content-Length: 2 Connection: keep-alive ok
このステップでは、Kubernetes APIサーバーが各ワーカーノードのKubelet APIにアクセスできるようにRBACによるアクセス許可を設定します。
メトリックやログの取得、Pod内でのコマンドの実行には、Kubelet APIへのアクセスが必要です。
まずはインスタンスにアクセスします。
gcloud compute ssh controller-0
kube-apiserver-to-kubeletという名前で
ClusterRoleを作ります。
このロールに、Kubelet APIにアクセスしてポッドの管理に関連するタスクを実行する権限を付与します。
cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f - apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: annotations: rbac.authorization.kubernetes.io/autoupdate: "true" labels: kubernetes.io/bootstrapping: rbac-defaults name: system:kube-apiserver-to-kubelet rules: - apiGroups: - "" resources: - nodes/proxy - nodes/stats - nodes/log - nodes/spec - nodes/metrics verbs: - "*" EOF
Kubernetes APIサーバーは、 --kubelet-client-certificate
フラグで定義したクライアント証明書を使って、kubernetes
ユーザーとしてKubeletに対して認証を行います。
system:kube-apiserver-to-kubelet
のClusterRoleをkubernetes
ユーザーにバインドします。
cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f - apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: system:kube-apiserver namespace: "" roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:kube-apiserver-to-kubelet subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: kubernetes EOF
このステップでは、Kubernetes APIサーバーの前段におく外部ロードバランサーをプロビジョニングします。
kubernetes-the-hard-way
の静的IPアドレスがこのロードバランサーにアタッチされます。
外部ロードバランサーのネットワークリソースを作ります。
{ KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \ --region $(gcloud config get-value compute/region) \ --format 'value(address)') gcloud compute http-health-checks create kubernetes \ --description "Kubernetes Health Check" \ --host "kubernetes.default.svc.cluster.local" \ --request-path "/healthz" gcloud compute firewall-rules create kubernetes-the-hard-way-allow-health-check \ --network kubernetes-the-hard-way \ --source-ranges 209.85.152.0/22,209.85.204.0/22,35.191.0.0/16 \ --allow tcp gcloud compute target-pools create kubernetes-target-pool \ --http-health-check kubernetes gcloud compute target-pools add-instances kubernetes-target-pool \ --instances controller-0,controller-1,controller-2 gcloud compute forwarding-rules create kubernetes-forwarding-rule \ --address ${KUBERNETES_PUBLIC_ADDRESS} \ --ports 6443 \ --region $(gcloud config get-value compute/region) \ --target-pool kubernetes-target-pool }
kubernetes-the-hard-way
のstatic IPアドレスを取得します
KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \ --region $(gcloud config get-value compute/region) \ --format 'value(address)')
Kubrenetesのバージョン情報を取得するHTTPリクエストを飛ばしてみます
curl --cacert ca.pem https://${KUBERNETES_PUBLIC_ADDRESS}:6443/version
例
{ "major": "1", "minor": "12", "gitVersion": "v1.12.0", "gitCommit": "0ed33881dc4355495f623c6f22e7dd0b7632b7c0", "gitTreeState": "clean", "buildDate": "2018-09-27T16:55:41Z", "goVersion": "go1.10.4", "compiler": "gc", "platform": "linux/amd64" }
このステップでは、3つのKubernetesワーカーノードをブートストラップします。
下記のコンポーネントを各ノードにインストールします。
runc、gVisor、container networking plugin、containerd、kubelet、kube-proxy
このステップのコマンドは、worker-0
、worker-1
、worker-2
の各ワーカーノードで実行する必要があります。
gcloudコマンド経由で各コントローラーインスタンスにログインをしてください。
gcloud compute ssh worker-0
tmuxを使えば、同時に複数のインスタンスにコマンド実行ができます。
こっちをみてみてね。
使うライブラリをインストールします。
{ sudo apt-get update sudo apt-get -y install socat conntrack ipset }
wget -q --show-progress --https-only --timestamping \ https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.12.0/crictl-v1.12.0-linux-amd64.tar.gz \ https://storage.googleapis.com/kubernetes-the-hard-way/runsc-50c283b9f56bb7200938d9e207355f05f79f0d17 \ https://github.com/opencontainers/runc/releases/download/v1.0.0-rc5/runc.amd64 \ https://github.com/containernetworking/plugins/releases/download/v0.6.0/cni-plugins-amd64-v0.6.0.tgz \ https://github.com/containerd/containerd/releases/download/v1.2.0-rc.0/containerd-1.2.0-rc.0.linux-amd64.tar.gz \ https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubectl \ https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kube-proxy \ https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubelet
インストールする先のディレクトリを作ります。
sudo mkdir -p \ /etc/cni/net.d \ /opt/cni/bin \ /var/lib/kubelet \ /var/lib/kube-proxy \ /var/lib/kubernetes \ /var/run/kubernetes
ワーカーのバイナリをインストールします。
{ sudo mv runsc-50c283b9f56bb7200938d9e207355f05f79f0d17 runsc sudo mv runc.amd64 runc chmod +x kubectl kube-proxy kubelet runc runsc sudo mv kubectl kube-proxy kubelet runc runsc /usr/local/bin/ sudo tar -xvf crictl-v1.12.0-linux-amd64.tar.gz -C /usr/local/bin/ sudo tar -xvf cni-plugins-amd64-v0.6.0.tgz -C /opt/cni/bin/ sudo tar -xvf containerd-1.2.0-rc.0.linux-amd64.tar.gz -C / }
現在のGCEインスタンスのPodのCIDR範囲を取得します。
POD_CIDR=$(curl -s -H "Metadata-Flavor: Google" \ http://metadata.google.internal/computeMetadata/v1/instance/attributes/pod-cidr)
bridge
ネットワークの設定ファイルを作ります。
cat <<EOF | sudo tee /etc/cni/net.d/10-bridge.conf { "cniVersion": "0.3.1", "name": "bridge", "type": "bridge", "bridge": "cnio0", "isGateway": true, "ipMasq": true, "ipam": { "type": "host-local", "ranges": [ [{"subnet": "${POD_CIDR}"}] ], "routes": [{"dst": "0.0.0.0/0"}] } } EOF
loopback
ネットワークの設定ファイルを作ります。
cat <<EOF | sudo tee /etc/cni/net.d/99-loopback.conf { "cniVersion": "0.3.1", "type": "loopback" } EOF
containerd
の設定ファイルを作ります。
sudo mkdir -p /etc/containerd/
cat << EOF | sudo tee /etc/containerd/config.toml [plugins] [plugins.cri.containerd] snapshotter = "overlayfs" [plugins.cri.containerd.default_runtime] runtime_type = "io.containerd.runtime.v1.linux" runtime_engine = "/usr/local/bin/runc" runtime_root = "" [plugins.cri.containerd.untrusted_workload_runtime] runtime_type = "io.containerd.runtime.v1.linux" runtime_engine = "/usr/local/bin/runsc" runtime_root = "/run/containerd/runsc" [plugins.cri.containerd.gvisor] runtime_type = "io.containerd.runtime.v1.linux" runtime_engine = "/usr/local/bin/runsc" runtime_root = "/run/containerd/runsc" EOF
containerd.service
systemdのユニットファイルを作ります。
cat <<EOF | sudo tee /etc/systemd/system/containerd.service [Unit] Description=containerd container runtime Documentation=https://containerd.io After=network.target [Service] ExecStartPre=/sbin/modprobe overlay ExecStart=/bin/containerd Restart=always RestartSec=5 Delegate=yes KillMode=process OOMScoreAdjust=-999 LimitNOFILE=1048576 LimitNPROC=infinity LimitCORE=infinity [Install] WantedBy=multi-user.target EOF
{ sudo mv ${HOSTNAME}-key.pem ${HOSTNAME}.pem /var/lib/kubelet/ sudo mv ${HOSTNAME}.kubeconfig /var/lib/kubelet/kubeconfig sudo mv ca.pem /var/lib/kubernetes/ }
kubelet-config.yaml
設定ファイルを作ります。
cat <<EOF | sudo tee /var/lib/kubelet/kubelet-config.yaml kind: KubeletConfiguration apiVersion: kubelet.config.k8s.io/v1beta1 authentication: anonymous: enabled: false webhook: enabled: true x509: clientCAFile: "/var/lib/kubernetes/ca.pem" authorization: mode: Webhook clusterDomain: "cluster.local" clusterDNS: - "10.32.0.10" podCIDR: "${POD_CIDR}" resolvConf: "/run/systemd/resolve/resolv.conf" runtimeRequestTimeout: "15m" tlsCertFile: "/var/lib/kubelet/${HOSTNAME}.pem" tlsPrivateKeyFile: "/var/lib/kubelet/${HOSTNAME}-key.pem" EOF
kubelet.service
systemdユニットファイルを作ります。
cat <<EOF | sudo tee /etc/systemd/system/kubelet.service [Unit] Description=Kubernetes Kubelet Documentation=https://github.com/kubernetes/kubernetes After=containerd.service Requires=containerd.service [Service] ExecStart=/usr/local/bin/kubelet \\ --config=/var/lib/kubelet/kubelet-config.yaml \\ --container-runtime=remote \\ --container-runtime-endpoint=unix:///var/run/containerd/containerd.sock \\ --image-pull-progress-deadline=2m \\ --kubeconfig=/var/lib/kubelet/kubeconfig \\ --network-plugin=cni \\ --register-node=true \\ --v=2 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF
sudo mv kube-proxy.kubeconfig /var/lib/kube-proxy/kubeconfig
kube-proxy-config.yaml
設定ファイルを作ります。
cat <<EOF | sudo tee /var/lib/kube-proxy/kube-proxy-config.yaml kind: KubeProxyConfiguration apiVersion: kubeproxy.config.k8s.io/v1alpha1 clientConnection: kubeconfig: "/var/lib/kube-proxy/kubeconfig" mode: "iptables" clusterCIDR: "10.200.0.0/16" EOF
kube-proxy.service
systemdユニットファイルを作ります。
cat <<EOF | sudo tee /etc/systemd/system/kube-proxy.service [Unit] Description=Kubernetes Kube Proxy Documentation=https://github.com/kubernetes/kubernetes [Service] ExecStart=/usr/local/bin/kube-proxy \\ --config=/var/lib/kube-proxy/kube-proxy-config.yaml Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF
{ sudo systemctl daemon-reload sudo systemctl enable containerd kubelet kube-proxy sudo systemctl start containerd kubelet kube-proxy }
登録されているKubernetesノードの一覧を表示させます。
gcloud compute ssh controller-0 \ --command "kubectl get nodes --kubeconfig admin.kubeconfig"
例
NAME STATUS ROLES AGE VERSION worker-0 Ready <none> 35s v1.12.0 worker-1 Ready <none> 36s v1.12.0 worker-2 Ready <none> 36s v1.12.0
このステップでは、admin
ユーザーのcredenialに基づいた、kubectl
コマンドラインユーティリティ用のkubeconfigファイルを生成します。
各kubeconfigは、Kubernetes APIサーバーと接続できる必要があります。
高可用性をサポートするために、Kubernetes APIサーバーの前段にある外部ロードバランサーに割り当てられたIPアドレスが使われています。
adminユーザーとして認証するのに適したkubeconfigファイルを生成します。
{ KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \ --region $(gcloud config get-value compute/region) \ --format 'value(address)') kubectl config set-cluster kubernetes-the-hard-way \ --certificate-authority=ca.pem \ --embed-certs=true \ --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 kubectl config set-credentials admin \ --client-certificate=admin.pem \ --client-key=admin-key.pem kubectl config set-context kubernetes-the-hard-way \ --cluster=kubernetes-the-hard-way \ --user=admin kubectl config use-context kubernetes-the-hard-way }
remoteのKubernetesクラスターのヘルスチェックを確認します。
kubectl get componentstatuses
例
NAME STATUS MESSAGE ERROR controller-manager Healthy ok scheduler Healthy ok etcd-1 Healthy {"health":"true"} etcd-2 Healthy {"health":"true"} etcd-0 Healthy {"health":"true"}
remoteのKubernetesクラスタのノードの一覧を取得します。
kubectl get nodes
例
NAME STATUS ROLES AGE VERSION worker-0 Ready <none> 117s v1.12.0 worker-1 Ready <none> 118s v1.12.0 worker-2 Ready <none> 118s v1.12.0
11. Podのネットワークルートのプロビジョニング
ノードにスケジュールされたPodは、ノードのPodのCIDR範囲からIPアドレスを受け取ります。
この時点では、ネットワークルートが見つからないため、Podは異なるノードで実行されている他のPodと通信できません。
このステップでは、ノードのPod CIDR範囲をノードの内部IPアドレスにマップするための、各ワーカーノードのルートを作成します。
このセクションでは、kubernetes-the-hard-way
VPCネットワーク内でルートを作るために必要な情報を集めます。
各ワーカーインスタンスの内部IPアドレスとPod CIDR範囲を表示させます。
for instance in worker-0 worker-1 worker-2; do gcloud compute instances describe ${instance} \ --format 'value[separator=" "](networkInterfaces[0].networkIP,metadata.items[0].value)' done
例
10.240.0.20 10.200.0.0/24 10.240.0.21 10.200.1.0/24 10.240.0.22 10.200.2.0/24
各ワーカーインスタンスにネットワークルートを設定します。
for i in 0 1 2; do gcloud compute routes create kubernetes-route-10-200-${i}-0-24 \ --network kubernetes-the-hard-way \ --next-hop-address 10.240.0.2${i} \ --destination-range 10.200.${i}.0/24 done
kubernetes-the-hard-way
のVPCネットワークの中のルートの一覧を出します。
gcloud compute routes list --filter "network: kubernetes-the-hard-way"
例
NAME NETWORK DEST_RANGE NEXT_HOP PRIORITY default-route-081879136902de56 kubernetes-the-hard-way 10.240.0.0/24 kubernetes-the-hard-way 1000 default-route-55199a5aa126d7aa kubernetes-the-hard-way 0.0.0.0/0 default-internet-gateway 1000 kubernetes-route-10-200-0-0-24 kubernetes-the-hard-way 10.200.0.0/24 10.240.0.20 1000 kubernetes-route-10-200-1-0-24 kubernetes-the-hard-way 10.200.1.0/24 10.240.0.21 1000 kubernetes-route-10-200-2-0-24 kubernetes-the-hard-way 10.200.2.0/24 10.240.0.22 1000
このステップでは、Kubernetesクラスタ内で動いているアプリケーションに、CoreDNSを使ったDNSベースのサービスディスカバリを提供するDNSアドオンをデプロイします。
coredns
クラスターアドオンをデプロイします。
kubectl apply -f https://storage.googleapis.com/kubernetes-the-hard-way/coredns.yaml
output
serviceaccount/coredns created clusterrole.rbac.authorization.k8s.io/system:coredns created clusterrolebinding.rbac.authorization.k8s.io/system:coredns created configmap/coredns created deployment.extensions/coredns created service/kube-dns created
kube-dns deploymentによって作られたPodの確認
kubectl get pods -l k8s-app=kube-dns -n kube-system
output
NAME READY STATUS RESTARTS AGE coredns-699f8ddd77-94qv9 1/1 Running 0 20s coredns-699f8ddd77-gtcgb 1/1 Running 0 20s
busybox
deploymentを作ります。
kubectl run busybox --image=busybox:1.28 --command -- sleep 3600
busybox
deploymentによって作られてPodを確認します。
kubectl get pods -l run=busybox
output
NAME READY STATUS RESTARTS AGE busybox-bd8fb7cbd-vflm9 1/1 Running 0 10s
busybox
Podのフルネームを取得します。
POD_NAME=$(kubectl get pods -l run=busybox -o jsonpath="{.items[0].metadata.name}")
busybox
Podの中からkubernetes
serviceのDNS lookupを行います。
kubectl exec -ti $POD_NAME -- nslookup kubernetes
output
Server: 10.32.0.10 Address 1: 10.32.0.10 kube-dns.kube-system.svc.cluster.local Name: kubernetes Address 1: 10.32.0.1 kubernetes.default.svc.cluster.local
このステップでは、Kubernetesクラスタが正しく機能していることを確認するためのタスクを実行します。
このステップでは保存されているデータの暗号化を確認します。
generic secretを作ります。
kubectl create secret generic kubernetes-the-hard-way \ --from-literal="mykey=mydata"
etcdに保存されているkubernetes-the-hard-way
secretをhexdumpします。
gcloud compute ssh controller-0 \ --command "sudo ETCDCTL_API=3 etcdctl get \ --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/etcd/ca.pem \ --cert=/etc/etcd/kubernetes.pem \ --key=/etc/etcd/kubernetes-key.pem\ /registry/secrets/default/kubernetes-the-hard-way | hexdump -C"
output
00000000 2f 72 65 67 69 73 74 72 79 2f 73 65 63 72 65 74 |/registry/secret| 00000010 73 2f 64 65 66 61 75 6c 74 2f 6b 75 62 65 72 6e |s/default/kubern| 00000020 65 74 65 73 2d 74 68 65 2d 68 61 72 64 2d 77 61 |etes-the-hard-wa| 00000030 79 0a 6b 38 73 3a 65 6e 63 3a 61 65 73 63 62 63 |y.k8s:enc:aescbc| 00000040 3a 76 31 3a 6b 65 79 31 3a dd 3f 36 6c ce 65 9d |:v1:key1:.?6l.e.| 00000050 b3 b1 46 1a ba ae a2 1f e4 fa 13 0c 4b 6e 2c 3c |..F.........Kn,<| 00000060 15 fa 88 56 84 b7 aa c0 7a ca 66 f3 de db 2b a3 |...V....z.f...+.| 00000070 88 dc b1 b1 d8 2f 16 3e 6b 4a cb ac 88 5d 23 2d |...../.>kJ...]#-| 00000080 99 62 be 72 9f a5 01 38 15 c4 43 ac 38 5f ef 88 |.b.r...8..C.8_..| 00000090 3b 88 c1 e6 b6 06 4f ae a8 6b c8 40 70 ac 0a d3 |;.....O..k.@p...| 000000a0 3e dc 2b b6 0f 01 b6 8b e2 21 29 4d 32 d6 67 a6 |>.+......!)M2.g.| 000000b0 4e 6d bb 61 0d 85 22 ea f4 d6 2d 0a af 3c 71 85 |Nm.a.."...-..<q.| 000000c0 96 27 c9 ec 90 e3 56 8c 94 a7 1c 9a 0e 00 28 11 |.'....V.......(.| 000000d0 18 28 f4 33 42 d9 57 d9 e3 e9 1c 38 e3 bc 1e c3 |.(.3B.W....8....| 000000e0 d2 47 f3 20 60 be b8 57 a7 0a |.G. `..W..| 000000ea
etcdキーは、k8s:enc:aescbc:v1:key1
というプレフィックスになっているはずです。
これは、aescbc
プロバイダがkey1
いう暗号化キーでデータを暗号化したことを表しています。
このステップではDeploymentの作成と管理ができているかを確認します。
nginx web serverのdeploymentを作成します。
kubectl run nginx --image=nginx
nginx
deploymentによってできたPodを確認します。
kubectl get pods -l run=nginx
output
NAME READY STATUS RESTARTS AGE nginx-dbddb74b8-6lxg2 1/1 Running 0 10s
このステップでは、port forwadingを使って外部からアプリケーションにアクセスできるかを確認します。
nginx
podのフルネームを取得します。
POD_NAME=$(kubectl get pods -l run=nginx -o jsonpath="{.items[0].metadata.name}")
ローカルの8080
ポートをnginx
Podの80
番ポートにフォワードします。
kubectl port-forward $POD_NAME 8080:80
output
Forwarding from 127.0.0.1:8080 -> 80 Forwarding from [::1]:8080 -> 80
別のターミナルからフォワードしたアドレスにHTTPリクエストを投げてみます。
curl --head http://127.0.0.1:8080
output
HTTP/1.1 200 OK Server: nginx/1.15.4 Date: Sun, 30 Sep 2018 19:23:10 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Tue, 25 Sep 2018 15:04:03 GMT Connection: keep-alive ETag: "5baa4e63-264" Accept-Ranges: bytes
もとのターミナルに戻ってnginx
Podへのフォワーディングを止めます。
Forwarding from 127.0.0.1:8080 -> 80 Forwarding from [::1]:8080 -> 80 Handling connection for 8080 ^C
このステップでは、コンテナのログの取得ができるかを確認します。
nginx
Podのログを表示します。
kubectl logs $POD_NAME
output
127.0.0.1 - - [30/Sep/2018:19:23:10 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.58.0" "-"
このステップではコンテナ内でのコマンド実行ができるかを確認します。
nginx
コンテナに入って、nginx -v
を実行してnginxのバージョンを表示します。
kubectl exec -ti $POD_NAME -- nginx -v
output
nginx version: nginx/1.15.4
このステップでは、Serviceを使ったアプリケーションの公開ができるかを確認します。
nginx
deploymentをNodePortを使って公開します。
kubectl expose deployment nginx --port 80 --type NodePort
nginx
serviceでアサインされたノードのポート取得します。
NODE_PORT=$(kubectl get svc nginx \ --output=jsonpath='{range .spec.ports[0]}{.nodePort}')
nginx
ノードポートに外部からアクセスできるようにファイヤーウォールのルール追加します。
gcloud compute firewall-rules create kubernetes-the-hard-way-allow-nginx-service \ --allow=tcp:${NODE_PORT} \ --network kubernetes-the-hard-way
ワーカーインスタンスから外部IPアドレスを取得します。
EXTERNAL_IP=$(gcloud compute instances describe worker-0 \ --format 'value(networkInterfaces[0].accessConfigs[0].natIP)')
外部IPアドレスとnginx
ノードポート組わせてHTTPリクエストを投げてみます。
curl -I http://${EXTERNAL_IP}:${NODE_PORT}
output
HTTP/1.1 200 OK Server: nginx/1.15.4 Date: Sun, 30 Sep 2018 19:25:40 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Tue, 25 Sep 2018 15:04:03 GMT Connection: keep-alive ETag: "5baa4e63-264" Accept-Ranges: bytes
gVisorを使って信頼されていないワークロードが動かせるかを確認します。
untrusted
Podを作ります。
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: untrusted annotations: io.kubernetes.cri.untrusted-workload: "true" spec: containers: - name: webserver image: gcr.io/hightowerlabs/helloworld:2.0.0 EOF
このセクションでは、割り当てられたワーカーノードを調べて、untrusted
PodがgVisor(runsc)の下で実行されていることを確認します。
untrusted
Podが実行されていることを確認します。
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE busybox-68654f944b-djjjb 1/1 Running 0 5m 10.200.0.2 worker-0 nginx-65899c769f-xkfcn 1/1 Running 0 4m 10.200.1.2 worker-1 untrusted 1/1 Running 0 10s 10.200.0.3 worker-0
untrusted
Podが実行されているノードの名前を取得します。
INSTANCE_NAME=$(kubectl get pod untrusted --output=jsonpath='{.spec.nodeName}')
ワーカーノードのsshでアクセスします。
gcloud compute ssh ${INSTANCE_NAME}
gVisorのもとで動いているコンテナの一覧を取得します。
sudo runsc --root /run/containerd/runsc/k8s.io list
I0930 19:27:13.255142 20832 x:0] *************************** I0930 19:27:13.255326 20832 x:0] Args: [runsc --root /run/containerd/runsc/k8s.io list] I0930 19:27:13.255386 20832 x:0] Git Revision: 50c283b9f56bb7200938d9e207355f05f79f0d17 I0930 19:27:13.255429 20832 x:0] PID: 20832 I0930 19:27:13.255472 20832 x:0] UID: 0, GID: 0 I0930 19:27:13.255591 20832 x:0] Configuration: I0930 19:27:13.255654 20832 x:0] RootDir: /run/containerd/runsc/k8s.io I0930 19:27:13.255781 20832 x:0] Platform: ptrace I0930 19:27:13.255893 20832 x:0] FileAccess: exclusive, overlay: false I0930 19:27:13.256004 20832 x:0] Network: sandbox, logging: false I0930 19:27:13.256128 20832 x:0] Strace: false, max size: 1024, syscalls: [] I0930 19:27:13.256238 20832 x:0] *************************** ID PID STATUS BUNDLE CREATED OWNER 79e74d0cec52a1ff4bc2c9b0bb9662f73ea918959c08bca5bcf07ddb6cb0e1fd 20449 running /run/containerd/io.containerd.runtime.v1.linux/k8s.io/79e74d0cec52a1ff4bc2c9b0bb9662f73ea918959c08bca5bcf07ddb6cb0e1fd 0001-01-01T00:00:00Z af7470029008a4520b5db9fb5b358c65d64c9f748fae050afb6eaf014a59fea5 20510 running /run/containerd/io.containerd.runtime.v1.linux/k8s.io/af7470029008a4520b5db9fb5b358c65d64c9f748fae050afb6eaf014a59fea5 0001-01-01T00:00:00Z I0930 19:27:13.259733 20832 x:0] Exiting with status: 0
untrusted
PodのIDを取得します。
POD_ID=$(sudo crictl -r unix:///var/run/containerd/containerd.sock \ pods --name untrusted -q)
untrusted
Podの中で動いてるwebserver
コンテナのIDを取得します。
CONTAINER_ID=$(sudo crictl -r unix:///var/run/containerd/containerd.sock \ ps -p ${POD_ID} -q)
gVisorのrunsc
コマンドを使って、webserver
コンテナの中で走っているプロセスを表示します。
sudo runsc --root /run/containerd/runsc/k8s.io ps ${CONTAINER_ID}
output
I0930 19:31:31.419765 21217 x:0] *************************** I0930 19:31:31.419907 21217 x:0] Args: [runsc --root /run/containerd/runsc/k8s.io ps af7470029008a4520b5db9fb5b358c65d64c9f748fae050afb6eaf014a59fea5] I0930 19:31:31.419959 21217 x:0] Git Revision: 50c283b9f56bb7200938d9e207355f05f79f0d17 I0930 19:31:31.420000 21217 x:0] PID: 21217 I0930 19:31:31.420041 21217 x:0] UID: 0, GID: 0 I0930 19:31:31.420081 21217 x:0] Configuration: I0930 19:31:31.420115 21217 x:0] RootDir: /run/containerd/runsc/k8s.io I0930 19:31:31.420188 21217 x:0] Platform: ptrace I0930 19:31:31.420266 21217 x:0] FileAccess: exclusive, overlay: false I0930 19:31:31.420424 21217 x:0] Network: sandbox, logging: false I0930 19:31:31.420515 21217 x:0] Strace: false, max size: 1024, syscalls: [] I0930 19:31:31.420676 21217 x:0] *************************** UID PID PPID C STIME TIME CMD 0 1 0 0 19:26 10ms app I0930 19:31:31.422022 21217 x:0] Exiting with status: 0
このステップでは、今までのステップで作ってきたリソースを削除します。
コントローラーとワーカーのインスタンスを落とします。
gcloud -q compute instances delete \ controller-0 controller-1 controller-2 \ worker-0 worker-1 worker-2
外部ロードバランサーのネットワークリソースを削除します。
{ gcloud -q compute forwarding-rules delete kubernetes-forwarding-rule \ --region $(gcloud config get-value compute/region) gcloud -q compute target-pools delete kubernetes-target-pool gcloud -q compute http-health-checks delete kubernetes gcloud -q compute addresses delete kubernetes-the-hard-way }
kubernetes-the-hard-way
ファイヤーウォールルールを削除します。
gcloud -q compute firewall-rules delete \ kubernetes-the-hard-way-allow-nginx-service \ kubernetes-the-hard-way-allow-internal \ kubernetes-the-hard-way-allow-external \ kubernetes-the-hard-way-allow-health-check
kubernetes-the-hard-way
VPCネットワークを削除します。
{ gcloud -q compute routes delete \ kubernetes-route-10-200-0-0-24 \ kubernetes-route-10-200-1-0-24 \ kubernetes-route-10-200-2-0-24 gcloud -q compute networks subnets delete kubernetes gcloud -q compute networks delete kubernetes-the-hard-way }
以上で完了です!
お疲れ様でした!