Kuberentesクラスタ 1.10 をkubeadmで構築
Kubernetes 1.10 の新機能
KubernetesはDockerのオーケストレーションツールとして使われており、Dockerコンテナの作成から、コンテナ監視管理、レプリケーション機能など多くの機能を提供している。3/26に1.10がリリースされ、新たにStorage機能やDNS機能が強化された。
Storage関連
Container Storage Interface(CSI)がBeta版に移行したらしく、CSIは新しいVolumeプラグインということ。またPersistentVolumeの更新もあり、Podで使用されているPersistentVolumeとPersistemtClaimの削除を防止する。これにより正しい順序でストレージが破棄されるようになるとのこと。
ネットワーク
CoreDNSをDNSプロバイダとして使用可能に、ただしBeta版。CoreDNSはバイナリで動作し、Configfileを記述するだけで簡単に機能する。
Kubernetesのサポートについて
1.10.x のSupportは Decenmber 2018まで。 各バージョンともに10か月間のサポートがある。1.8.x は2018/6月にサポートが終了する。
kubeadmによる Kubernetesクラスタの構築
Kubernetesをスクラッチで,1から構築する手順は公式にあるが、クラスタ間の通信のTLS対応や各コンポーネントの各種設定など、初心者にはそこそこ厳しい。Kuberetes公式Tutorialもscratchは難しいからやめとけと言わんばかりにMinikubeやkubeadmを勧めている。まずはkubeadmによる自動構築を試してみる。 今回の手順はKubernetes公式の手順を参考に躓いたポイントをまとめる。
Using kubeadm to Create a Cluster
VMの作成
多くのOSで導入可能。今回はCentOSを選択。
導入環境
# | 推奨 | |
---|---|---|
OS | CentOS7 | CentOS or Ubuntu |
CPU | 4Core | 2Core以上 |
メモリ | 4GB | 2GB以上 |
kubeadmのインストール
前提事項
各設定をユニークに
- Unique hostname, MAC address, and product_uuid for every node.
ホスト名、IPアドレスを固定化
- ホスト名設定:
hostnamectl set-hostname k8s-master
- IP固定化:
vi /etc/sysconfig/network-scripts/ifcfg-ens*
等で
SELinuxを無効
# vi /etc/selinux/config ... SELINUX=disabled ...
Firewalldを無効
Kubernetesは多くのポートを使うので、ひとまず無効に
systemctl stop firewalld systemctl disable firewalld
OS swapを無効
- Swap disabled. You MUST disable swap in order for the kubelet to work properly
- OS設定の
swap
が有効な場合`kubelet'の動作に影響があるため無効に
- OS設定の
swapの無効化(CentOS7)
/etc/fstab
を編集
※ 修正ミスするとOSが立ち上がらくなることがあるので注意
... ... /dev/mapper/cl-swap swap swap defaults 0 0
kubernetesのリポジトリを追加
kubernetes用のリポジトリを追加し、kubelet', 'kubeadm', 'kubectl
をインストールする。
cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg EOF
yum repolist
で追加を確認。
[root@k8s-master ~]# yum repolist Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile * base: ftp.tsukuba.wide.ad.jp * extras: ftp.tsukuba.wide.ad.jp * updates: ftp.tsukuba.wide.ad.jp repo id repo name status base/7/x86_64 CentOS-7 - Base 9,591 extras/7/x86_64 CentOS-7 - Extras 448 kubernetes/x86_64 Kubernetes 202 updates/7/x86_64 CentOS-7 - Updates 2,416 repolist: 12,657
kubelet kubeadm kubectl
をインストールし、サービス登録。
yum install -y kubelet kubeadm kubectl systemctl enable kubelet && systemctl start kubelet
ルーティング設定
RHEL系だと標準ではKubernetesの仮想ネットワークからルーティングされないようなので、有効にする。
cat <<EOF > /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF
sysctl --system
cgroup設定
kubeletでは同じcgoup driver
を使う必要があるため、設定内容を確認する
[root@k8s-master ~]# docker info | grep -i cgroup WARNING: You're not using the default seccomp profile Cgroup Driver: systemd [root@k8s-master ~]# cat /etc/systemd/system/kubelet.service.d/10-kubeadm.conf | grep -i cgroup-driver Environment="KUBELET_CGROUP_ARGS=--cgroup-driver=systemd"
今回はどちらもsystemd
のため問題がないが、もし異なる場合は下記を実行
sed -i "s/cgroup-driver=systemd/cgroup-driver=cgroupfs/g" /etc/systemd/system/kubelet.service.d/10-kubeadm.conf systemctl daemon-reload systemctl restart kubelet
kubeadm によるKuberetesの構築
kubeadmを使う準備が整った。kubeadmでkubernetesを構築する。
kubeadm init
を実行するだけで、クラスタが構築されるが、さまざまなオプションが用意されている。
kubeadm init [FLAG]
FLAG | 用途 |
---|---|
--apiserver-advertise-address string | k8sのAPIサーバのlisten IPアドレス. stringにipアドレスを記述 |
--apiserver-bind-port int32 | APIサーバのポートを指定。デフォルトは6443 |
--cert-dir string | k8s用の証明書保存ディレクトリ デフォルトは/etc/kubernetes/pki |
--config string | kubeadm用のConfigファイルを指定 |
--ignore-preflight-errors strings | Warning, Errorを無視してインストール |
--kubernetes-version string | 任意のバージョンのKubernetesをインストール デフォルトはstable-1.10 |
--pod-network-cidr string | podのサブネットを変更。stringに任意のサブネットを記述 |
--service-cidr string | サービスのVIPのサブネットを変更 デフォルトは10.96.0.0/12 |
--service-dns-domain string | サービスのドメインを変更 デフォルトはcluster.local |
その他オプションに CoreDNSの有効設定がある。
Auditing=true|false (ALPHA - default=false) CoreDNS=true|false (BETA - default=false) DynamicKubeletConfig=true|false (ALPHA - default=false) SelfHosting=true|false (ALPHA - default=false) StoreCertsInSecrets=true|false (ALPHA - default=false)
この中で--apiserver-advertise-address
, --kubernetes-version
, --service-cidr
, --pod-network-cidr
あたりは環境に応じて変更したほうがよさそう。Service-cidrに関してはk8s内部のIP帯と基幹ネットワークのPrivateIPが重複することもあり、k8sの対外通信自体はNAT処理が入るが、使用されるIP帯には注意が必要だろう。
kubeadmによる構築を実行
kubeadm init --apiserver-advertise-address '192.168.0.221' --kubernetes-version 1.10.2 --service-cidr '10.0.0.0/24' --pod-network-cidr '172.16.0.0/24'
kubeadm init
でエラーがでたらkubeadm reset
を実行し、再度kubeadm init
を実行。
[root@k8s-master ~]# kubeadm init --apiserver-advertise-address '192.168.0.221' --kubernetes-version 1.10.2 --service-cidr '10.0.0.0/24' --pod-network-cidr '172.16.0.0/24' [init] Using Kubernetes version: v1.10.2 [init] Using Authorization modes: [Node RBAC] [preflight] Running pre-flight checks. [WARNING Hostname]: hostname "k8s-master" could not be reached [WARNING Hostname]: hostname "k8s-master" lookup k8s-master on 192.168.0.1:53: no such host [WARNING FileExisting-crictl]: crictl not found in system path Suggestion: go get github.com/kubernetes-incubator/cri-tools/cmd/crictl [preflight] Starting the kubelet service [certificates] Generated ca certificate and key. [certificates] Generated apiserver certificate and key. [certificates] apiserver serving cert is signed for DNS names [k8s-master kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.0.0.1 192.168.0.221] [certificates] Generated apiserver-kubelet-client certificate and key. [certificates] Generated etcd/ca certificate and key. [certificates] Generated etcd/server certificate and key. [certificates] etcd/server serving cert is signed for DNS names [localhost] and IPs [127.0.0.1] [certificates] Generated etcd/peer certificate and key. [certificates] etcd/peer serving cert is signed for DNS names [k8s-master] and IPs [192.168.0.221] [certificates] Generated etcd/healthcheck-client certificate and key. [certificates] Generated apiserver-etcd-client certificate and key. [certificates] Generated sa key and public key. [certificates] Generated front-proxy-ca certificate and key. [certificates] Generated front-proxy-client certificate and key. [certificates] Valid certificates and keys now exist in "/etc/kubernetes/pki" [kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/admin.conf" [kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/kubelet.conf" [kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/controller-manager.conf" [kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/scheduler.conf" [controlplane] Wrote Static Pod manifest for component kube-apiserver to "/etc/kubernetes/manifests/kube-apiserver.yaml" [controlplane] Wrote Static Pod manifest for component kube-controller-manager to "/etc/kubernetes/manifests/kube-controller-manager.yaml" [controlplane] Wrote Static Pod manifest for component kube-scheduler to "/etc/kubernetes/manifests/kube-scheduler.yaml" [etcd] Wrote Static Pod manifest for a local etcd instance to "/etc/kubernetes/manifests/etcd.yaml" [init] Waiting for the kubelet to boot up the control plane as Static Pods from directory "/etc/kubernetes/manifests". [init] This might take a minute or longer if the control plane images have to be pulled. [apiclient] All control plane components are healthy after 18.501018 seconds [uploadconfig]?Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [markmaster] Will mark node k8s-master as master by adding a label and a taint [markmaster] Master k8s-master tainted and labelled with key/value: node-role.kubernetes.io/master="" [bootstraptoken] Using token: 3ugeo9.90nstqyd48q4esa7 [bootstraptoken] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials [bootstraptoken] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token [bootstraptoken] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster [bootstraptoken] Creating the "cluster-info" ConfigMap in the "kube-public" namespace [addons] Applied essential addon: kube-dns [addons] Applied essential addon: kube-proxy Your Kubernetes master has initialized successfully! To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ You can now join any number of machines by running the following on each node as root: kubeadm join 192.168.0.221:6443 --token 3ugeo9.90nstqyd48q4esa7 --discovery-token-ca-cert-hash sha256:43d8fe3e155ab1c2226bd12c5e9e72aacfe178c3a5566b874f1c4b5fc26757a4
Your Kubernetes master has initialized successfully!
と表示されていれば完了。
途中にWarningメッセージが出ている。ホスト名解決ができていないのかホスト名関連のエラー。気には留めておく。
[WARNING Hostname]: hostname "k8s-master" could not be reached [WARNING Hostname]: hostname "k8s-master" lookup k8s-master on 192.168.0.1:53: no such host [WARNING FileExisting-crictl]: crictl not found in system path
最後の一行のkubeadm join ~~
だが、これはクラスタノード(minion node)を組む際に使うもので、kubeadm導入済みの環境でコピペすればクラスタへ参加する。とても簡単。
kubectlによる接続
kubectl
では鍵による接続設定が必要。kubeadmが自動生成してくれているので、これをkubectlが読み取れる位置に変更する。
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
別の環境からkubectl
を実行する場合もこのadmin.conf
をコピーすれば接続が完了する。
Podネットワークの構築(CNI)
k8sのコンポーネントの起動確認kubectl get pods --all-namespaces
をするとkube-dns
が動作せず、他のコンポーネントもループしている。
[root@k8s-master ~]# kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS RESTARTS AGE kube-system etcd-k8s-master 1/1 Running 0 4s kube-system kube-apiserver-k8s-master 1/1 Running 0 4s kube-system kube-controller-manager-k8s-master 1/1 Running 0 4s kube-system kube-dns-86f4d74b45-7vqqq 0/3 Pending 0 8m kube-system kube-proxy-kzpgb 1/1 Running 0 8m kube-system kube-scheduler-k8s-master 1/1 Running 0 4s
これはk8sのContainer Network Interfaceが動作していないためなので、CNIをインストールを行う。
多くのサードパーティによるCNIが用意されている。
- Calico
- Canal
- Flannel
- Kube-router
- Romana
- Weave Net
今回はflannel
を使う。
kubeadmでflannelを使う場合はオプションに--pod-network-cidr=10.244.0.0/16
を指定しないと行けないらしい。
変えられそうなので調べたらkube-flannel.yml
の中に記述されており、書き換えれば良い。
wget https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml
65行目 "Network": "10.244.0.0/16",
を172.16.0.0/24
に
63 net-conf.json: | 64 { 65 "Network": "10.244.0.0/16", 66 "Backend": { 67 "Type": "vxlan" 68 } 69 }
flannelをインストール
kubectl apply -f kube-flannel.yml
k8sコンポーネントの起動状況を確認
kubectl get pods --all-namespaces
[root@k8s-master ~]# kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS RESTARTS AGE kube-system etcd-k8s-master 1/1 Running 0 37s kube-system kube-apiserver-k8s-master 1/1 Running 0 37s kube-system kube-controller-manager-k8s-master 1/1 Running 0 37s kube-system kube-dns-86f4d74b45-7vqqq 3/3 Running 0 31m kube-system kube-flannel-ds-fpskt 1/1 Running 0 46s kube-system kube-proxy-kzpgb 1/1 Running 0 31m kube-system kube-scheduler-k8s-master 1/1 Running 0 37s
kube-dns
が起動している。よさそう。
Podの作成
試しにPodを作成し、動作検証する。 kubeadmでは標準ではMasterノードではPodがデプロイされない設定になっているので、これを解除
[root@k8s-master ~]# kubectl taint nodes --all node-role.kubernetes.io/master- node "k8s-master" untainted
k8sはPodとServiceをデプロイするがマニフェストファイルyaml
で管理する。
テストとしてnginxをデプロイする。List記法を使い、Deployment
とService
をまとめて書いた。
nginx-test.yaml
apiVersion: v1 kind: List items: - apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx spec: replicas: 2 template: metadata: labels: run: nginx spec: containers: - name: nginx image: nginx:1.13 ports: - containerPort: 80 - apiVersion: v1 kind: Service metadata: name: nginx-nodeport spec: type: NodePort ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx
Pod, Serviceをデプロイ
[root@k8s-master ~]# kubectl create -f nginx-test.yaml deployment.extensions "nginx" created service "nginx-nodeport" created
kubectl get all
でpodとserviceを確認
[root@k8s-master ~]# kubectl get all NAME READY STATUS RESTARTS AGE pod/nginx-bbc784cf-qqkbk 1/1 Running 0 1m pod/nginx-bbc784cf-wm8n4 1/1 Running 0 1m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 43m service/nginx-nodeport NodePort 10.0.0.30 <none> 80:30062/TCP 1m NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deployment.apps/nginx 2 2 2 2 1m NAME DESIRED CURRENT READY AGE replicaset.apps/nginx-bbc784cf 2 2 2 1m
よさそう。
kubeadm init
で指定したservice CIDR10.0.0.0/24
になっている。
ついでにコンテナIPも見てみる。
kubectl describe
で Pod,コンテナの状態を確認
[root@k8s-master ~]# kubectl describe pod/nginx-bbc784cf-qqkbk Name: nginx-bbc784cf-qqkbk Namespace: default Node: k8s-master/192.168.0.221 Start Time: Sat, 28 Apr 2018 13:33:24 -0400 Labels: pod-template-hash=66734079 run=nginx Annotations: <none> Status: Running IP: 172.16.0.3 Controlled By: ReplicaSet/nginx-bbc784cf Containers: nginx: Container ID: docker://5be8d67afbfe477c92519e215eeccc1b13163480ce5f072ad95d3c1d2ce6f140 Image: nginx:1.13 Image ID: docker-pullable://docker.io/nginx@sha256:80e2f223b2a53cfcf3fd491521e5fb9b4004d42dfc391c76011bcdd9565643df Port: 80/TCP Host Port: 0/TCP State: Running Started: Sat, 28 Apr 2018 13:33:36 -0400 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-rs2wt (ro) Conditions: Type Status Initialized True Ready True PodScheduled True Volumes: default-token-rs2wt: Type: Secret (a volume populated by a Secret) SecretName: default-token-rs2wt Optional: false QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 3m default-scheduler Successfully assigned nginx-bbc784cf-qqkbk to k8s-master Normal SuccessfulMountVolume 3m kubelet, k8s-master MountVolume.SetUp succeeded for volume "default-token-rs2wt" Normal Pulling 3m kubelet, k8s-master pulling image "nginx:1.13" Normal Pulled 2m kubelet, k8s-master Successfully pulled image "nginx:1.13" Normal Created 2m kubelet, k8s-master Created container Normal Started 2m kubelet, k8s-master Started container
こちらもPodのIPが172.16.0.3
になっていることを確認。
サービスのバインドポートがservice/nginx-nodeport NodePort 10.0.0.30 <none> 80:30062/TCP
のため、クライアント環境からk8s向けに192.168.0.221:30062
でアクセス
無事 nginx が表示された。
とりあえずkubeadmを用いてPodが立つところまでできた。
以上。