LoginSignup
3
6

More than 3 years have passed since last update.

Ubuntu 上に Kubernetes + Istio + HAProxy の HA環境をコピペで作る

Last updated at Posted at 2020-05-28

はじめに

この記事で目指す構成は、ほぼタイトルの通りですが、

「kubeadmで作ったHA構成のk8sクラスタにIstioを入れて、HAProxyでプロキシする」

です。

kubeadm 公式で、将来的にもっと簡単にHA構成出来るようにすると言っているので、すぐに陳腐化するかもしれませんが…

想定するサーバー構成

  • プロキシ
  • マスターノード × n
  • ワーカーノード × n

の構成を目指します。
僕は、ノードは2つずつの環境で作成しました。

使い方

タイトル通り、基本的には順番にコピペしていくだけです。
項目の頭にどのサーバー用のコマンド化が書いてあり、関連付けは以下の通りです。

頭文字 サーバー
P プロキシ
M マスターノード
W ワーカーノード

記事中にスクリプトがいくつか出てきますが、変更可能個所がある場合は大体冒頭で変数を定義しています。
要件に合わせて、適宜変更してください。

記事中にいくつかコピペできないところが出てきますので、ご注意ください。

コピペコマンド

それでは、粛々とコピペしていきましょう。

[P/M/W] サーバー初期セットアップ

各種アップデートとタイムゾーン設定

sudo apt update && sudo apt upgrade -y
sudo timedatectl set-timezone Asia/Tokyo

[P] HAProxy のセットアップ

インストール

sudo apt install haproxy -y

cfgファイル作成

変数
HOSTS マスターノードのアドレス(スペース区切り、配列)
HOSTS="192.168.1.110 192.168.1.111"
sudo mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg~

writeHost() {
sudo sh -c "cat << EOF >> /etc/haproxy/haproxy.cfg

# ==================
# $1
# ==================
frontend $1
    bind *:$2
    mode $3
    default_backend $1

backend $1
    balance     roundrobin
    mode        $3
    option      tcp-check
EOF"
COUNT=1
for host in ${HOSTS}; do
sudo sh -c "cat << EOF >> /etc/haproxy/haproxy.cfg
    server $1-${COUNT} ${host}:$2 check
EOF"
((COUNT++))
done
}

sudo sh -c "cat << EOF > /etc/haproxy/haproxy.cfg
# ==================
# global
# ==================
global
    log /dev/log    local0
    log /dev/log    local1 notice
    chroot /var/lib/haproxy
defaults
    log global
    mode    http
    option  httplog clf
    option  dontlognull
EOF"

writeHost k8s-api 6443 tcp
writeHost k8s-http 80 http
# writeHost k8s-https 443
sudo service haproxy restart

writeHost k8s-http 80 http の個所を適宜増やしていけば、他のポートにも対応可能です。

※HAProxyの前にさらにnginxがある場合

nginxの設定ファイルでproxy_http_version 1.1;を設定しないと、エラー426が起こります。
istioがhttp1.0に対応していない事が原因なようです。

[M/W] Docker のセットアップ

インストール

sudo apt-get update
sudo apt-get install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io

現在のユーザーで Docker を実行可能に

sudo groupadd docker
sudo usermod -aG docker $(id -u -n)

(Docker バージョン指定が必要な場合)

変数
VERSION_STRING インストールするDockerのバージョン
sudo apt-cache showpkg docker-ce
VERSION_STRING=5:18.09.1~3-0~ubuntu-xenial
sudo apt-get install -y docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING containerd.io

[M/W] kubeadm のインストール

sudo apt-get update && sudo apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

(kubeadm バージョン指定が必要な場合)

変数
VERSION_STRING インストールするDockerのバージョン
sudo apt-cache showpkg kubeadm
VERSION_STRING=1.18.9-00
sudo apt install -y kubeadm=$VERSION_STRING kubelet=$VERSION_STRING kubectl=$VERSION_STRING

[M/W] swapを永続的にオフ

sudo swapoff -a
sudo sed -i 's:/swap.img:#/spap.img:g' /etc/fstab

[M] 最初のマスターノードセットアップ

kubeadm init

変数
LOAD_BALANCER_DNS HAProxyのアドレス
LOAD_BALANCER_PORT HAProxyが待ち受けているポート
POD_SUBNET calicoで使用するサブネット
LOAD_BALANCER_DNS=192.168.1.120
LOAD_BALANCER_PORT=6443
POD_SUBNET=192.168.128.0/17
cat <<EOF > config.yaml
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: stable
apiServer:
  certSANs:
  - "${LOAD_BALANCER_DNS}"
controlPlaneEndpoint: "${LOAD_BALANCER_DNS}:${LOAD_BALANCER_PORT}"
networking:
  podSubnet: "${POD_SUBNET}"
EOF
kubeadm config migrate --old-config config.yaml --new-config kubeadm-config.yaml
rm ~config.yaml
sudo kubeadm init --config=kubeadm-config.yaml

出力結果のコピーを忘れずに! ↓表示例(コピペコマンドではありません)

Your Kubernetes control-plane 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 control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:

  kubeadm join 192.168.1.120:6443 --token 77pipk.mh0vazty24yrhedt \
    --discovery-token-ca-cert-hash sha256:99d7dd0f6774d12cb95bca85bf03a666f11d45a1d4a729808974073b405ea126 \
    --control-plane

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.1.120:6443 --token 77pipk.mh0vazty24yrhedt \
    --discovery-token-ca-cert-hash sha256:99d7dd0f6774d12cb95bca85bf03a666f11d45a1d4a729808974073b405ea126

設定のコピー

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

calicoを入れる

変数
CIDR calicoで使用するサブネット(先のPOD_SUBNETと同様)
CIDR=192.168.128.0/17
curl -L -O https://docs.projectcalico.org/v3.8/manifests/calico.yaml
sed -i "s:192.168.0.0/16:${CIDR}:g" ./calico.yaml
kubectl apply -f ./calico.yaml

他のマスターに証明書を送信

sshが証明書認証になっていないと、 scp コマンドの度にパスワードを聞かれます。

USER=$(id -u -n)
CONTROL_PLANE_IPS="192.168.1.110 192.168.1.111"
for host in ${CONTROL_PLANE_IPS}; do
    sudo scp /etc/kubernetes/pki/ca.crt "${USER}"@$host:
    sudo scp /etc/kubernetes/pki/ca.key "${USER}"@$host:
    sudo scp /etc/kubernetes/pki/sa.key "${USER}"@$host:
    sudo scp /etc/kubernetes/pki/sa.pub "${USER}"@$host:
    sudo scp /etc/kubernetes/pki/front-proxy-ca.crt "${USER}"@$host:
    sudo scp /etc/kubernetes/pki/front-proxy-ca.key "${USER}"@$host:
    sudo scp /etc/kubernetes/pki/etcd/ca.crt "${USER}"@$host:etcd-ca.crt
    sudo scp /etc/kubernetes/pki/etcd/ca.key "${USER}"@$host:etcd-ca.key
    sudo scp /etc/kubernetes/admin.conf "${USER}"@$host:
done

[M] その他のマスターノードセットアップ

認証情報を適切な場所に配置

USER=$(id -u -n)
sudo mkdir -p /etc/kubernetes/pki/etcd
sudo mv /home/${USER}/ca.crt /etc/kubernetes/pki/
sudo mv /home/${USER}/ca.key /etc/kubernetes/pki/
sudo mv /home/${USER}/sa.pub /etc/kubernetes/pki/
sudo mv /home/${USER}/sa.key /etc/kubernetes/pki/
sudo mv /home/${USER}/front-proxy-ca.crt /etc/kubernetes/pki/
sudo mv /home/${USER}/front-proxy-ca.key /etc/kubernetes/pki/
sudo mv /home/${USER}/etcd-ca.crt /etc/kubernetes/pki/etcd/ca.crt
sudo mv /home/${USER}/etcd-ca.key /etc/kubernetes/pki/etcd/ca.key
sudo mv /home/${USER}/admin.conf /etc/kubernetes/admin.conf

kubeadm join

マスター1のkubeadm initで得たコマンドのうち、--control-planeついている方sudo付きで実行します。

↓例(コピペコマンドではありません)

kubeadm join 192.168.1.120:6443 --token 77pipk.mh0vazty24yrhedt \
    --discovery-token-ca-cert-hash sha256:99d7dd0f6774d12cb95bca85bf03a666f11d45a1d4a729808974073b405ea126 \
    --control-plane

設定のコピー

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

[W] ワーカーノードセットアップ

マスター1のkubeadm initで得たコマンドのうち、--control-planeついていない方sudo付きで実行します。

↓例(コピペコマンドではありません)

sudo kubeadm join 192.168.1.120:6443 --token 77pipk.mh0vazty24yrhedt \
    --discovery-token-ca-cert-hash sha256:99d7dd0f6774d12cb95bca85bf03a666f11d45a1d4a729808974073b405ea126

トークンとシークレットが無効になった場合

こちらの記事を参照してください。

[M] istioのインストール

デフォルト状態でインストール

curl -L https://git.io/getLatestIstio | sh -
for f in ./istio*; do
  cd $f
  break
done
sudo mv bin/istioctl /usr/local/bin/
istioctl manifest apply -y

削除する場合

istioctl manifest generate --set profile=demo | kubectl delete -f -

デフォルト + ダッシュボードをインストール

curl -L https://git.io/getLatestIstio | sh -
for f in ./istio*; do
  cd $f
  break
done
sudo mv bin/istioctl /usr/local/bin/
istioctl manifest apply -y\
  --set addonComponents.grafana.enabled=true\
  --set addonComponents.kiali.enabled=true\
  --set addonComponents.prometheus.enabled=true

削除する場合

istioctl manifest generate \
  --set addonComponents.grafana.enabled=true\
  --set addonComponents.kiali.enabled=true\
  --set addonComponents.prometheus.enabled=true
  | kubectl delete -f -

NodePortに変更

istio 1.5.1での設定です。
istio-ingressgatewaytypeNodePort に変更して、extenralIPs に マスターノードのIPを列挙しています。

変数
IPS マスターノードのIP(スペース区切り、配列)
IPS="192.168.1.110 192.168.1.111"
cat <<EOF > network.yaml
apiVersion: v1
kind: Service
metadata:
  annotations: null
  labels:
    app: istio-ingressgateway
    istio: ingressgateway
    release: istio
  name: istio-ingressgateway
  namespace: istio-system
spec:
  ports:
  - name: status-port
    port: 15020
    targetPort: 15020
  - name: http2
    port: 80
    targetPort: 80
  - name: https
    port: 443
  - name: kiali
    port: 15029
    targetPort: 15029
  - name: prometheus
    port: 15030
    targetPort: 15030                                                                                                                                                                      - name: grafana                                                                                                                                                                            port: 15031                                                                                                                                                                              targetPort: 15031
  - name: tracing
    port: 15032
    targetPort: 15032
  - name: tls
    port: 15443
    targetPort: 15443
  - name: tcp
    port: 31400
  selector:
    app: istio-ingressgateway
    istio: ingressgateway
  type: NodePort
  externalIPs:
EOF
for ip in ${IPS}; do
sh -c "cat << EOF >> network.yaml
    - ${ip}
EOF"
done
kubectl apply -f network.yaml

envoyの自動インジェクト設定

変数
NAMESPACE 自動インジェクション対象の名前空間
NAMESPACE=ns-v1
kubectl label namespace ${NAMESPACE} istio-injection=enabled

(option) [M/W] プライベートDockerレジストリに対応

変数
REGISTRY プライベートDockerレジストリのアドレス

注意: 名前空間が毎に保存されるので、対応したい名前空間が複数ある場合は namspace の指定が必要です。

REGISTRY=registory.example.com
docker login $REGISTRY
DOCKERCONFIGJSON=$(cat ~/.docker/config.json | base64 -w 0)
cat <<EOF > private-registry-cred.yaml
apiVersion: v1
kind: Secret
metadata:
  name: regcred
data:
  .dockerconfigjson: ${DOCKERCONFIGJSON}
type: kubernetes.io/dockerconfigjson
EOF
kubectl apply -f private-registry-cred.yaml

この状態で、manifestにimagePullSecretsを追加すると、設定済みのプライベートDockerレジストリからpull可能になります。

apiVersion: v1
kind: Pod
metadata:
  name: private-reg
spec:
  containers:
  - name: private-reg-container
    image: <your-private-image>
  imagePullSecrets:
  - name: regcred

参考

https://docs.docker.com/install/linux/docker-ce/ubuntu/
https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
http://grugrut.hatenablog.jp/entry/2019/06/23/143533
https://qiita.com/megasys1968/items/b84f79b9c3f77de3d4a3
https://bbrfkr.hatenablog.jp/entry/2018/03/15/094536
https://esakat.github.io/esakat-blog/posts/kubernetes-dashboard-v2.0.0/
https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/

istio
https://qiita.com/Ladicle/items/e949b0f68ac18b7a95d8
https://istio.io/docs/setup/getting-started/#uninstall
https://istio.io/docs/setup/install/istioctl/#generate-a-manifest-before-installation

3
6
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
3
6