41
46

More than 5 years have passed since last update.

kubeadmを使ってオンプレミスのプロキシ環境下にKubernetesクラスタをデプロイする(CentOS 7.3)

Last updated at Posted at 2018-03-13

クラスタのデプロイ・管理が大変なのでほんとはk8sのマネージドサービス使いたい...GKEとか。
でもオンプレミスで運用せざるを得ないことってありますよね。しかもプロキシ環境下で。

そんな状況下でk8sクラスタを構築する方法の備忘録です。

kubeadm

公式が提供しているk8sクラスタを構築するためのツールです。現在のバージョンはまだBeta版ですが、2018年内にGA予定のようです。

この記事の内容は基本的には公式ドキュメントの焼き直し+α(プロキシ設定など)です。

Beta版ということもあり、クラスタデータを保持するetcdの冗長化、およびMasterコンポーネントが複数存在するようなHigh Availability構成のクラスタは単純にkubeadmを使うだけでは構築できません。
今回はHA構成までは考えず、今回利用したkubeadm v1.9がカバーする範囲である単一Master構成のクラスタを構築します。

このあたりはGA時点では対応されるんでしょうか。

環境

  • CentOS 7.3(master, worker)
  • プロキシ経由でインターネットに接続可能な環境

k8sクラスタ構成

  • master: 単一構成
  • podネットワーク: flannel
  • コンテナランタイム: docker

バージョン

  • kubernetes v1.9.0
  • kubeadm v1.9.0
  • docker v1.12.6
  • flannel v0.9.1

準備

kubeadmでk8sクラスタを構築するための準備です。各master/worker nodeすべてで実施します。rootで実施する前提です。

/etc/hostsの設定

以下のように新しい行にホスト名に対応するIPアドレスを追記します。

[ip_address] [hostname]

以下のコマンド実行で追記できます(単一NIC、イーサネットの前提です)。

echo $(ip a | grep 'en\|eth0' | grep "inet" | cut -d' ' -f6 | cut -d/ -f1) $(hostname) >> /etc/hosts

yumのプロキシ設定

kubeadmはじめdocker, kubeletなどのk8sの動作に必要なパッケージはyumでインストールします。
プロキシ経由でyumが利用できるよう/etc/yum.confに以下を設定しておきます。

proxy = http://[proxy_host]:[proxy_port]

以下のコマンド実行で設定できます。

echo proxy = http://[proxy_host]:[proxy_port] >> /etc/yum.conf
  • プロキシで認証が必要な場合は以下も追加します。

    echo proxy_username = [proxy_user] >> /etc/yum.conf
    echo proxy_password = [proxy_pass] >> /etc/yum.conf
    

firewall無効化

systemctl disable firewalld
systemctl stop firewalld

SELinux無効化

setenforce 0

/etc/selinux/configを編集しdisableにしておきます。

SELINUX=disabled

以下のコマンドでdisableに変更できます。

sed -e "/^SELINUX=enforcing$/s/SELINUX=enforcing/SELINUX=disabled/" -i.bak /etc/selinux/config

MACアドレスおよびproduct_uuidがすべてのノード間で重複していないことの確認

公式ドキュメントに

Unique hostname, MAC address, and product_uuid for every node

とあるので確認しておきます。

  • MACアドレス確認

    ip link
    
  • product_uuid確認

    cat /sys/class/dmi/id/product_uuid
    

swapを無効化

これも公式ドキュメントに

Swap disabled. You MUST disable swap in order for the kubelet to work properly.

とあるので無効にしておきます。

swapoff -a
sed -e "/^UUID=[a-z0-9-]* swap/s/^/# /" -i.bak /etc/fstab
cat /etc/fstab

Kubernetesコンポーネントが使用するポートが他プロセスで使用されていないか確認

k8sの各コンポーネントが利用するポートが使用されていないことを確認します。

  • Master node

    Protocol Direction Port Range Purpose
    TCP Inbound 6443* Kubernetes API server
    TCP Inbound 2379-2380 etcd server client API
    TCP Inbound 10250 Kubelet API
    TCP Inbound 10251 kube-scheduler
    TCP Inbound 10252 kube-controller-manager
    TCP Inbound 10255 Read-only Kubelet API
  • Worker nodes

    Protocol Direction Port Range Purpose
    TCP Inbound 10250 Kubelet API
    TCP Inbound 10255 Read-only Kubelet API
    TCP Inbound 30000-32767 NodePort Services*

*部分は設定により変更可能です。今回はk8s master/node上でk8s管理外のアプリケーションプロセスが動作することは想定していないため、デフォルト設定とします。

docker v1.12.6インストール

Kubernetesではv1.12が推奨(1.13や17.03でも動作確認済みとのこと)されているため、 v1.12.6をインストールします。

dockerインストール手順もほぼ公式ドキュメントの焼き直しです。

必要なyumリポジトリの有効化

yum update -y
yum install -y yum-utils
yum-config-manager --add-repo https://docs.docker.com/v1.13/engine/installation/linux/repo_files/centos/docker.repo
yum makecache fast

dockerパッケージのインストール

yum install -y docker-engine-1.12.6-1.el7.centos

dockerのproxy設定

Docker Hubなどインターネット上のコンテナイメージリポジトリからイメージを取得するため、プロキシ経由で接続可能な設定をする必要があります。

mkdir -p /etc/systemd/system/docker.service.d
cat <<EOF > /etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://[proxy_user:proxy_pass@][proxy_host]:[proxy_port]" "HTTPS_PROXY=http://[proxy_user:proxy_pass@][proxy_host]:[proxy_port]" "NO_PROXY=localhost,127.0.0.1,[master_node_ip],[worker_nodes_ip],10.96.0.0/12,10.244.0.0/16"
EOF

NO_PROXYにはすべてのk8s master/worker nodeのIPアドレスを指定します。また、k8sの各Serviceに割り振られる仮想IP(10.96.0.0/12)、および後述するpodネットワークプラグインが展開するOverlayネットワークのIPアドレス範囲(10.244.0.0/16)をCIDRで記載しておきます。

これをしないとkubeadmでクラスタ構築するときに、preflightチェックで異なるホスト間のPodおよびServiceの通信がプロキシ経由でルーティングされちゃうよ!という旨のWarningが出力され、実際にうまく通信してくれませんでした。

proxy設定の反映

systemctl daemon-reload

dockerを起動&自動起動設定

systemctl enable docker && systemctl start docker

proxy設定が反映されていることを確認

$ docker info | grep Proxy
Http Proxy: http://[proxy_host]:[proxy_port]
Https Proxy: http://[proxy_host]:[proxy_port]
No Proxy: localhost,127.0.0.1,[master_node_ip],[worker_nodes_ip],10.96.0.0/12,10.244.0.0/16

dockerの動作確認

docker単体で動作可能なことを確認します。確認できたらもう利用しないのでイメージは消しておきます。

docker run --rm hello-world
docker rmi docker.io/library/hello-world

一般ユーザからdockerを利用可能にする

groupadd docker
usermod -aG docker [user_name]
systemctl restart docker

ログアウト, 再ログインを実施し設定を反映します。

ここまででdockerのインストールが完了しました。
dockerはコンテナイメージの取得、コンテナの起動、削除をこれから構築するk8sクラスタからの指示で行うことになります。

本番環境で利用する場合の設定(ストレージドライバ)

CentOS/RHELではdockerコンテナ/イメージごとのストレージを変更差分ごとに管理するため、デフォルトでdevicemapperというストレージドライバを利用します。

devicemapperはデフォルト設定の場合loop-lvmというモードで動作しています。このモードはコンテナ利用時のディスクI/Oのパフォーマンスが良くないので、プロダクション環境で運用する場合はdirect-lvmモードに変更することを公式が推奨しています。

詳細は公式ドキュメントに記載がありますが、ホストマシン上にLVMとthin poolを作成する必要があります。docker v17.06以降だとdaemon.jsonに設定を記載すると自動で作ってくれるみたいですね。

kubeadmインストール、kubenetesクラスタの構築

kubadmのプロキシ設定

設定内容はdockerのプロキシ設定時と同様です。ホスト上の環境変数として指定します。

環境変数が常に有効となるように.bash_profileに追記し反映します。

cat <<EOF >> ~/.bash_profile
PROXY_PORT=[proxy_port]
PROXY_HOST=[proxy_host]
http_proxy=http://[proxy_user:proxy_pass@]\$PROXY_HOST:\$PROXY_PORT
HTTP_PROXY=\$http_proxy
https_proxy=\$http_proxy
HTTPS_PROXY=\$http_proxy
no_proxy="localhost,127.0.0.1,[master_node_ip],[worker_nodes_ip],10.96.0.0/12,10.244.0.0/16"
EOF

source ~/.bash_profile

kubeadm, kubelet, kubectlパッケージリポジトリを追加

kubeadmとk8sの動作に必要なパッケージをインストールするためのyumリポジトリを追加します。

以下、簡単な説明です。下記以外のk8sコンポーネントはkubeadmがコンテナとして起動してくれます。

  • kubelet: pod, コンテナを起動する役割を持つ、クラスタ内のすべてのホストマシンに存在するコンポーネント
  • kubectl: K8sクラスタと対話するためのCLIユーティリティ
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
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

kubeadm, kubelet, kubectlパッケージインストール(v1.9.0)

yum install -y kubelet-1.9.0-0 kubeadm-1.9.0-0 kubectl-1.9.0-0

K8sの通信が正しくルーティングされるよう設定

k8sはiptablesを更新することでクラスタ内の各Pod間のルーティングを実現しています。

RHEL/CentOSの場合以下の設定をしないと通信が正しくルーティングされないようです。

cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

kubeletを一度起動し、Cgroup Driverがdockerとkubelet間で一致していることを確認

CentOSデフォルトだとkubeletはsystemd、Dockerはcgroupfsを使うはずなので、利用するドライバの指定はDockerインストール時に先に実施しておいてもいいです。

systemctl enable kubelet && systemctl start kubelet
cat /etc/systemd/system/kubelet.service.d/10-kubeadm.conf | grep KUBELET_CGROUP_ARG
docker info | grep Cgroup
systemctl stop kubelet

どちらもcgroup-driver=systemdとなっていればOK

  • 異なる場合
    以下を実施後再度確認します。

    cat << EOF > /etc/docker/daemon.json
    {
    "exec-opts": ["native.cgroupdriver=systemd"]
    }
    EOF"
    systemctl restart docker
    

masterでのみ実施する作業

masterの初期化

まずはdry-runしてみる

--kubernetes-versionでk8sのバージョンを指定しています。また、--apiserver-advertise-addressでmasterのIPアドレスを指定します。

kubeadmはworker node追加時の認証のためにトークンを払い出すのですが、利用期限が決まっておりデフォルトで24時間有効です。今回は検証用途であり、あとでworker nodeを追加したりする可能性があるため、--token-ttl 0を指定し認証トークンの利用期限を無期限にしています。

--pod-network-cidrにはプロキシ設定でも指定したOverlayネットワークのIPアドレス範囲(10.244.0.0/16)をCIDR形式で指定します。

kubeadm init --kubernetes-version 1.9.0 --apiserver-advertise-address=$(ip a | grep 'en\|eth0' | grep "inet" | cut -d' ' -f6 | cut -d/ -f1) --pod-network-cidr=10.244.0.0/16 --token-ttl 0 --dry-run

以下が出力されれば問題なく実行できているので、実際に初期化実行します。

[dryrun]?Finished dry-running successfully. Above are the resources that would be created.
初期化
kubeadm init --kubernetes-version 1.9.0 --apiserver-advertise-address=$(ip a | grep 'en\|eth0' | grep "inet" | cut -d' ' -f6 | cut -d/ -f1) --pod-network-cidr=10.244.0.0/16 --token-ttl 0

以下が出力されれば初期化に成功しています。kubeadm join以降の出力はworker nodeを追加する際に実行するコマンドです。

Your Kubernetes master has initialized successfully!

To start using your cluster, you need to run (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:
  http://kubernetes.io/docs/admin/addons/

You can now join any number of machines by running the following on each node
as root:

  kubeadm join --token [token] [K8s_master_host]:[port] --discovery-token-ca-cert-hash sha256:[hash]

kube-apiserverと対話可能にする設定

初期化時に出力されていた以下のコマンドを実行します。

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Podネットワークアドオンのデプロイ

kubeadmはOverlayネットワークを展開するところまでは面倒見てくれないので、別途Podネットワークプラグインをクラスタにデプロイします。これをしないとずっとmasterのステータスがNot Ready状態となりk8sが機能しません。

今回はflannelを利用します。
master初期化時の--pod-network-cidrやプロキシ設定で指定したIPアドレス範囲(10.244.0.0/16)はこのflannelが展開するOverlayネットワークで利用します。

kubectl apply -f  https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml

master上でkube-dns PodがRunningになっていることを確認

Podネットワークが動作しているとしばらくしてkube-dnsがRunning状態になるはずなので確認します。

$ kubectl get pods -n kube-system
NAME                                               READY     STATUS    RESTARTS   AGE
etcd-[k8s_master_host]                             1/1       Running   0          10m
kube-apiserver-[k8s_master_host]                   1/1       Running   0          10m
kube-controller-manager-[k8s_master_host]          1/1       Running   0          10m
kube-dns-6f4fd4bdf-b7kw9                           3/3       Running   0          10m
kube-flannel-ds-c2r9b                              1/1       Running   0          10m
kube-proxy-s9krr                                   1/1       Running   0          10m
kube-scheduler-[k8s_master_host]                   1/1       Running   0          10m

masterのstatusがReadyになっていることを確認

masterの状態がReadyとなり、k8sクラスタとして利用できる状態になっていることを確認します。

$ kubectl get nodes
NAME                       STATUS    ROLES     AGE       VERSION
[k8s_master_host]          Ready     master    10m       v1.9.0

masterでもPod起動がスケジュールされるようにmasterへのPod配置を制限するtaintを削除

デフォルトではmasterへPodが配置されないよう、taintという機能によりmasterへのPodスケジューリングが制限されています。

リソースが不足していたりmaster単体で動かす場合は、master nodeに設定されているtaintを削除します。

kubectl taint nodes --all node-role.kubernetes.io/master-

worker nodeでのみ実施する作業

worker nodeの追加

masterの初期化時に出力されたtoken, hash値を引数に指定します。

kubeadm join --token [token] [K8s_master_host]:6443 --discovery-token-ca-cert-hash sha256:[hash]

以下が出れば成功

Node join complete:
* Certificate signing request sent to master and response
  received.
* Kubelet informed of new secure connection details.

Run 'kubectl get nodes' on the master to see this machine join.

K8sクラスタにworker nodeが追加されReadyになっていることをmasterで確認

$ kubectl get nodes
NAME                       STATUS    ROLES     AGE       VERSION
[k8s_master_host]          Ready     master    10m       v1.9.0
[k8s_worker_host]          Ready     master    10m       v1.9.0

以上でオンプレミス、プロキシ環境下のホスト上でk8sクラスタを動作させることができました。

これでプロキシ環境下でもkubectl applyやhelmなどを利用してアプリケーションをクラスタ上に展開していくことができます。

参考サイト

41
46
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
46