API Aggregationを有効化してPrometheusのメトリクスからHorizonPodAutoscalerでPodのオートスケールをする
やたら長いタイトルですが…
KubernetesではAPI Aggregationといって、Custom Metrics API Serverを用意しkube-apiserver
と連携することでAPIを拡張することができます。例えば今回のタイトルにもある通り、Prometheusが取得したメトリクスをAPIから取得できるようにすることができます。この記事では以下を可能とするKubernetesの設定を説明します。
API Aggregationの有効化
API Aggregationを有効化するにはkube-apiserver
とkube-controller-manager
に設定が必要になります。
まず、kube-controller-manager
に以下のオプションを設定して再起動します。
--horizontal-pod-autoscaler-use-rest-clients=true
次にkube-apiserver
の認証方式において、x509証明書認証を有効化するために、CA証明書を用意します。CA証明書のファイルパスを/etc/kubernetes/certs/ca.crt
とします。
さらにkube-apiserver
とCustom Metrics API Serverとが連携するために使うクライアント証明書と秘密鍵、そしてクライアント証明書の署名に使ったCAのCA証明書を用意します。それぞれのファイルパスを/etc/kubernetes/certs/proxy-client.crt
、/etc/kubernetes/certs/proxy-client.key
、/etc/kubernetes/certs/proxy-ca.crt
とします。
その後kube-apiserver
に以下のオプションを設定します
--client-ca-file=/etc/kubernetes/certs/ca.crt --requestheader-client-ca-file=/etc/kubernetes/certs/proxy-ca.crt --requestheader-allowed-names='' --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --proxy-client-cert-file=/etc/kubernetes/certs/proxy-client.crt --proxy-client-key-file=/etc/kubernetes/certs/proxy-client.key
最後にkube-apiserver
の再起動を行うのですが、もし既に--client-ca-file
の値を指定していて今回CA証明書を変更する場合、既にAPIサーバ間連携に使用するConfigMap extension-apiserver-authentication
ができてしまっているので、これをあらかじめ削除しておきます。
kubectl -n kube-system delete configmap extension-apiserver-authentication
その後、kube-apiserver
を再起動します。
これでAPI Aggregationの設定は完了です。
Prometheus用のCustom Metrics API Serverの構築とkube-apiserverとの連携
Prometheus用のCustom Metrics API Serverを構築し、kube-apiserverにAPIエンドポイントを作成してkube-apiserver
とCustom Metrics API Serverとを連携させます。
前提条件として名前空間kube-system
にPrometheusは構築済みであるとします。ここではPrometheusサーバ(port: 9090)のホスト名をprometheus-server
であるとします。
まずはCustom Metrics API Serverを構築するためのKubernetes Manifestをダウンロードします。
git clone https://github.com/DirectXMan12/k8s-prometheus-adapter cd k8s-prometheus-adapter
ダウンロードしてきたManifestの中にあるPrometheusサーバの指定を変更します。
sed -i 's/prometheus.prom.svc:9090/prometheus-server/g' deploy/manifests/custom-metrics-apiserver-deployment.yaml
また、Manifest内でリソースを作成する名前空間をkube-system
に変更します。
sed -i 's/namespace: custom-metrics/namespace: kube-system/g' deploy/manifests/*
さらにPullしてくるCustom Metrics API Serverコンテナイメージのタグを付与します。
sed -i 's/directxman12\/k8s-prometheus-adapter/directxman12\/k8s-prometheus-adapter:advanced-config/g' deploy/manifests/custom-metrics-apiserver-deployment.yaml
次にCustom Metrics API Serverのサーバ証明書と秘密鍵を作成します。ファイル名はそれぞれserving.crt
、serving.key
とします。
作成したサーバ証明書と秘密鍵を使用してSecret cm-adapter-serving-certs
を作成します。
kubectl -n kube-system create secret generic --from-file=serving.crt=serving.crt --from-file=serving.key=serving.key cm-adapter-serving-certs
最後にCustom Metrics API Serverを構築します。
kubectl create -f deploy/manifests/
構築がうまくいっていれば、APIを叩くと以下のような出力が得られると思います。
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | jq . { "kind": "APIResourceList", "apiVersion": "v1", "groupVersion": "custom.metrics.k8s.io/v1beta1", "resources": [ { "name": "pods/fs_sector_writes", "singularName": "", "namespaced": true, "kind": "MetricValueList", "verbs": [ "get" ] }, <中略> { "name": "jobs.batch/kube_pod_status_phase", "singularName": "", "namespaced": true, "kind": "MetricValueList", "verbs": [ "get" ] } ] }
PrometheusのメトリクスからPodをオートスケールする
では実際に構築したCustom Metrics API Serverを使ってオートスケールを実現してみましょう。 まずはテスト用にDeployment、Serviceを作ります。
kubectl create deploy httpd --image httpd kubectl expose deploy httpd --port 80 kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpd ClusterIP 172.16.132.62 <none> 80/TCP 10s kubernetes ClusterIP 172.16.0.1 <none> 443/TCP 56m
次にHorizontalPodAutoScalerをDeployment httpd
に対して作ります。
cat << EOF > hpa-httpd.yaml apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata: name: httpd namespace: default spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: httpd minReplicas: 1 maxReplicas: 8 metrics: - type: Pods pods: metricName: cpu_usage targetAverageValue: 1m EOF kubectl create -f hpa-httpd.yaml
HPAが作成出来たら、以下のスクリプトを実行してPodに負荷をかけます。
cat << EOF > hpa-test.sh #!/bin/sh count=1 while(true) do curl http://172.16.132.62 > /dev/null 2>&1 & echo access count = \$((count++)) done EOF chmod 755 hpa-test.sh ./hpa-test.sh
するとPodが増えていく様が見て取れるはずです。
KubernetesでHorizontal Pod Autoscalerを使えるようにする
KubernetesにおけるHorizontal Pod Autoscaler(HPA)とは、Podの過負荷時(CPU使用量増、メモリ使用量増など)においてPodをオートスケーリングするリソースです。DeploymentやReplicaSetに紐付けて使います。
HPAを使ってオートスケーリングを実現するには、Podの負荷を監視する必要があります。つまり種々のメトリクス(CPU使用率、メモリ使用率など)を取得する必要があります。
Kubernetesでもっとも簡単にメトリクス取得する方法はおそらくHeapsterという監視ソフトウェアを使うことです。Helmを使って簡単にインストールできます。
# helm install stable/heapster --namespace kube-system
Kubernetes v.1.10だと、HPAを実現するデフォルトのメトリクス取得先はAggregation APIになっており、Heapsterのメトリクスを見てくれません。そこでkube-controller-manager
の起動オプションに次のオプションを加えます。
--horizontal-pod-autoscaler-use-rest-clients=false
これでHeapsterを使ってオートスケーリングを実現することができます。
Haproxy Ingress Controllerの導入
OpenShiftではおなじみのroute機能を、Kubernetes上でもIngressを使って再現してみたいと思います。
まずはDNSワイルドカードの有効化から。今回は*.ha-kubernetes.internal
というアドレスをhaproxyポッドに割り当てます。
DNSサーバの設定
# vi /etc/dnsmasq.conf
address=/ha-kubernetes.internal/192.168.0.89
# systemctl restart dnsmasq
例のごとくマルチマスターKubernetes環境を前提とするので、フロントエンドのロードバランサ(これもhaproxy)に対し80や443ポートにアクセスが来たら、マスターの同一ポートにリクエストを流すように設定します。
フロントエンドロードバランサの設定(haproxy-*)
# vi /etc/haproxy/haproxy.cfg
... frontend router_http *:80 default_backend router_http frontend router_https *:443 default_backend router_https frontend router_stat *:1936 default_backend router_stat ... backend router_http balance leastconn server master1 kube-master-01.bbrfkr.mydns.jp:80 check server master2 kube-master-02.bbrfkr.mydns.jp:80 check backup server master3 kube-master-03.bbrfkr.mydns.jp:80 check backup backend router_https balance leastconn server master1 kube-master-01.bbrfkr.mydns.jp:443 check server master2 kube-master-02.bbrfkr.mydns.jp:443 check backup server master3 kube-master-03.bbrfkr.mydns.jp:443 check backup backend router_stat balance leastconn server master1 kube-master-01.bbrfkr.mydns.jp:1936 check server master2 kube-master-02.bbrfkr.mydns.jp:1936 check backup server master3 kube-master-03.bbrfkr.mydns.jp:1936 check backup
# systemctl restart haproxy
デフォルトでkube-apiserverはnodePortに30000-32767の間しか指定できないので、この縛りを緩くします。
nodeportレンジの変更(kube-master-*)
# sed -i 's/KUBE_API_ARGS="/KUBE_API_ARGS="--service-node-port-range 1-32767 /g' /etc/kubernetes/apiserver # systemctl restart kube-apiserver
これからが実際のHaproxy Ingress Controllerの設定です。
haproxy ingress controllerの作成
- デフォルトページ(404)作成
# vi ingress-default-deployment.yaml
apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: run: ingress-default-backend name: ingress-default-backend namespace: kube-system spec: replicas: 1 selector: matchLabels: run: ingress-default-backend template: metadata: labels: run: ingress-default-backend spec: containers: - name: ingress-default-backend image: gcr.io/google_containers/defaultbackend:1.0 ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: labels: run: ingress-default-backend name: ingress-default-backend namespace: kube-system spec: ports: - name: port-1 port: 8080 protocol: TCP targetPort: 8080 selector: run: ingress-default-backend
# kubectl create -f ingress-default-deployment.yaml
- controllerのコンフィグ作成
# vi haproxy-configmap.yaml
apiVersion: v1 data: dynamic-scaling: "true" backend-server-slots-increment: "4" kind: ConfigMap metadata: name: haproxy-configmap namespace: kube-system
# kubectl create -f haproxy-configmap.yaml
- ingress controllerのデプロイ
# vi haproxy-ingress-deployment.yaml
apiVersion: v1 kind: ServiceAccount metadata: name: haproxy-ingress namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: name: haproxy-ingress-clusterrole rules: - apiGroups: - "" resources: - configmaps - endpoints - nodes - pods - secrets verbs: - list - watch - apiGroups: - "" resources: - nodes verbs: - get - apiGroups: - "" resources: - services verbs: - get - list - watch - apiGroups: - "extensions" resources: - ingresses verbs: - get - list - watch - apiGroups: - "" resources: - events verbs: - create - patch - apiGroups: - "extensions" resources: - ingresses/status verbs: - update --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: Role metadata: name: haproxy-ingress-role namespace: kube-system rules: - apiGroups: - "" resources: - configmaps - pods - secrets - namespaces verbs: - get - apiGroups: - "" resources: - configmaps resourceNames: # Defaults to "<election-id>-<ingress-class>" # Here: "<ingress-controller-leader>-<haproxy>" # This has to be adapted if you change either parameter # when launching the haproxy-ingress-controller. - "ingress-controller-leader-haproxy" verbs: - get - update - apiGroups: - "" resources: - configmaps verbs: - create - apiGroups: - "" resources: - endpoints verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: RoleBinding metadata: name: haproxy-ingress-role-nisa-binding namespace: kube-system roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: haproxy-ingress-role subjects: - kind: ServiceAccount name: haproxy-ingress namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: haproxy-ingress-clusterrole-nisa-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: haproxy-ingress-clusterrole subjects: - kind: ServiceAccount name: haproxy-ingress namespace: kube-system --- apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: run: haproxy-ingress name: haproxy-ingress namespace: kube-system spec: replicas: 1 selector: matchLabels: run: haproxy-ingress template: metadata: labels: run: haproxy-ingress spec: containers: - name: haproxy-ingress image: quay.io/jcmoraisjr/haproxy-ingress args: - --default-backend-service=kube-system/ingress-default-backend - --default-ssl-certificate=kube-system/tls-secret - --configmap=$(POD_NAMESPACE)/haproxy-configmap - --reload-strategy=native ports: - name: http containerPort: 80 - name: https containerPort: 443 - name: stat containerPort: 1936 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace serviceAccountName: haproxy-ingress
# kubectl create -f haproxy-ingress-deployment.yaml
- ingress controllerの外部公開サービス作成
# vi haproxy-ingress-svc.yaml
apiVersion: v1 kind: Service metadata: labels: run: haproxy-ingress name: haproxy-ingress namespace: kube-system spec: type: NodePort ports: - name: port-1 port: 80 protocol: TCP targetPort: 80 nodePort: 80 - name: port-2 port: 443 protocol: TCP targetPort: 443 nodePort: 443 - name: port-3 port: 1936 protocol: TCP targetPort: 1936 nodePort: 1936 selector: run: haproxy-ingress
# kubectl create -f haproxy-ingress-svc.yaml
ここまでで、Haproxy Ingress Controllerの構成はおしまいです。実際に動作確認をしてみましょう。
動作確認
- エンドポイントサービスの作成
# vi httpd-deployment.yaml
apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: run: httpd name: httpd spec: replicas: 1 selector: matchLabels: run: httpd template: metadata: labels: run: httpd spec: containers: - name: httpd image: httpd ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: labels: run: httpd name: httpd namespace: default spec: ports: - name: port-1 port: 80 protocol: TCP targetPort: 80 selector: run: httpd
# kubectl create -f httpd-deployment.yaml
- Ingressの作成
# vi httpd-ingress.yaml
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: httpd spec: rules: - host: test.ha-kubernetes.internal http: paths: - path: / backend: serviceName: httpd servicePort: 80
# kubectl create -f httpd-ingress.yaml
- ブラウザでtest.ha-kubernetes.internalにアクセス
Kubernetes環境にDashboardとDNSサービスをデプロイする
前回作成したマルチマスターKubernetes環境はKubernetesの最小構成なので、今回はDashboardとDNSサービスをデプロイしたいと思います。 まずはDashboardのデプロイから。
Dashboardの設定
- kube-controller-managerの設定で、ServiceAccountがAPIサーバとの通信に使うルートCA証明書を持つように設定する
# sed -i 's@KUBE_CONTROLLER_MANAGER_ARGS="@KUBE_CONTROLLER_MANAGER_ARGS="--root-ca-file=/etc/kubernetes/certs/apiserver.crt @g' /etc/kubernetes/controller-manager # systemctl restart kube-controller-manager
- 既存のServiceAccount「default」を削除(自動的に新しいCA証明書を持つServiceAccountが再作成されます)
# kubectl delete sa default # kubectl delete sa default -n kube-system # kubectl delete sa default -n kube-public
- APIサーバ側でsystem:anonymousがNamespace"kube-system"のResource"*"にRW権限を付ける
- ABACの設定
# vi /etc/kubernetes/abac-policy.json
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"system:anonymous", "namespace": "kube-system", "resource": "*"}}
- APIサーバの認可機能で、RBACも適用するように設定する。
# sed -i 's/--authorization-mode=ABAC/--authorization-mode=RBAC,ABAC/g' /etc/kubernetes/apiserver # systemctl restart kube-apiserver
- manifestを落としてくる
# curl -O https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml
- manifestの修正
- Dashboard自体のベーシック認証を有効化する
- オプション指定
- Dashboard自体のベーシック認証を有効化する
... spec: containers: - name: kubernetes-dashboard image: k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3 ports: - containerPort: 8443 protocol: TCP args: - --auto-generate-certificates - --authentication-mode # ここを追加 - basic # ここを追加 # Uncomment the following line to manually specify Kubernetes API server Host # If not specified, Dashboard will attempt to auto discover the API server and connect # to it. Uncomment only if the default does not work. # - --apiserver-host=http://my-address:port ...
- kubernetes-dashboardポッドのデプロイ
# kubectl create -f kubernetes-dashboard.yaml
次にDNSサービスのデプロイですねー
kube-dns設定
# sed -i 's/KUBELET_ARGS="/KUBELET_ARGS="--cluster-dns=172.16.0.2 --cluster-domain=cluster.local /g' /etc/kubernetes/kubelet # systemctl restart kubelet
- manifestをダウンロード
# curl -O https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/kube-dns.yaml.sed # mv kube-dns.yaml.sed kube-dns.yaml
# sed -i "s/\$DNS_SERVER_IP/172.16.0.2/g" kube-dns.yaml # sed -i "s/\$DNS_DOMAIN/cluster.local/g" kube-dns.yaml
- kube-dnsポッドのデプロイ
# kubectl create -f kube-dns.yaml
これでDashboardとDNSサービス用のPodなりServiceなりが正常に上がるはずです。
Dashboardはこんな感じ。
DNSサービスの稼働確認をするために、httpdポッドを二つ、別のノードに上げてみましょう。Masterノードで以下を叩きます。
# kubectl create deploy --image httpd httpd-1 # kubectl create deploy --image httpd httpd-2 # kubectl expose deploy httpd-1 --port 80 # kubectl expose deploy httpd-2 --port 80
ポッドが上がったら、以下のコマンドでcurlをそれぞれのポッドにインストールします。
# kubectl exec <httpd-1のポッド> -- apt-get update # kubectl exec <httpd-1のポッド> -- apt-get install -y curl # kubectl exec <httpd-2のポッド> -- apt-get update # kubectl exec <httpd-2のポッド> -- apt-get install -y curl
curlをインストールしたら、互いのサービスに対して名前解決ができるかを確かめます。
# kubectl exec <httpd-1のポッド> -- curl httpd-2 # kubectl exec <httpd-2のポッド> -- curl httpd-1
複数マスターを持つ高可用性Kubernetesクラスタを作る
先日、keepalivedを用いてhaproxyを冗長化する記事を上げましたが、この高可用性ロードバランサを用いて複数マスターを持つ高可用性Kubernetestクラスタを作ってみたので、その手順を公開いたします。
環境
アーキテクチャはシンプルで、kubeletやkubectlのAPIリクエストを直接マスターに送るのではなく、間にhaproxyを挟むことによってマスターの冗長化を実現しています。
なお、利用OSはCentOS 7.4になります。
手順
以降、実際の手順です。
共通設定(haproxy-01, haproxy-02, kube-master-01, kube-master-02, kube-master-03, kube-node-01, kube-node-02)
- hosts設定
# vi /etc/hosts
192.168.0.82 kube-master-01.bbrfkr.mydns.jp 192.168.0.83 kube-master-02.bbrfkr.mydns.jp 192.168.0.84 kube-master-03.bbrfkr.mydns.jp 192.168.0.85 kube-node-01.bbrfkr.mydns.jp 192.168.0.86 kube-node-02.bbrfkr.mydns.jp 192.168.0.87 haproxy-01.bbrfkr.mydns.jp 192.168.0.88 haproxy-02.bbrfkr.mydns.jp
- SELinux、firewalldの無効化
検証のため、無効化します。
# sed -i 's/SELINUX=.*/SELINUX=permissive/g' /etc/selinux/config # systemctl disable firewalld # reboot
LBの構築(haproxy-*)
- haproxy、keepalivedのインストール(haproxy-01, haproxy-02)
# yum -y install haproxy keepalived
- haproxyの設定(haproxy-01, haproxy-02)
# vi /etc/haproxy/haproxy.cfg
frontend api *:6443 default_backend api frontend etcd *:2379 default_backend etcd backend api balance leastconn server master1 kube-master-01.bbrfkr.mydns.jp:6443 check server master2 kube-master-02.bbrfkr.mydns.jp:6443 check backup server master3 kube-master-03.bbrfkr.mydns.jp:6443 check backup backend etcd balance leastconn server master1 kube-master-01.bbrfkr.mydns.jp:2379 check server master2 kube-master-02.bbrfkr.mydns.jp:2379 check backup server master3 kube-master-03.bbrfkr.mydns.jp:2379 check backup
- haproxyの起動と自動起動設定(haproxy-01, haproxy-02)
# systemctl enable haproxy # systemctl start haproxy
- keepalivedの設定(haproxy-01)
# vi /etc/keepalived/keepalived.conf
vrrp_script chk_haproxy { script "systemctl is-active haproxy" } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 1 priority 101 virtual_ipaddress { 192.168.0.89 } track_script { chk_haproxy } }
- keepalivedの設定(haproxy-02)
# vi /etc/keepalived/keepalived.conf
vrrp_script chk_haproxy { script "systemctl is-active haproxy" } vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 1 priority 100 virtual_ipaddress { 192.168.0.89 } track_script { chk_haproxy } }
- keepalivedの起動と自動起動設定(haproxy-01, haproxy-02)
# systemctl enable keepalived # systemctl start keepalived
Dockerのインストール(kube-*)
- パッケージのインストール
# yum -y install docker
- コンテナボリューム用ディスクのセットアップ
# cat <<EOF > /etc/sysconfig/docker-storage-setup DEVS=/dev/vda VG=docker-vg EOF # docker-storage-setup
- ヘアピンNATの有効化(これをしないと、Podが自分自身のServiceにアクセスできなくなる...)
# sed -i "s/OPTIONS='/OPTIONS='--userland-proxy=false /g" /etc/sysconfig/docker
- サービスの起動と自動起動設定
# systemctl enable docker # systemctl start docker
etcdのインストール(kube-master-*)
- パッケージのインストール(kube-master-*)
# yum -y install etcd
- 設定ファイルの書き換え(kube-master-01)
# vi /etc/etcd/etcd.conf
#[Member] ETCD_NAME=kube-master-01 ETCD_DATA_DIR="/var/lib/etcd/default.etcd" ETCD_LISTEN_PEER_URLS="http://192.168.0.82:2380" ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" #[Clustering] ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.0.82:2380" ETCD_ADVERTISE_CLIENT_URLS="http://192.168.0.82:2379" ETCD_INITIAL_CLUSTER="kube-master-01=http://192.168.0.82:2380,kube-master-02=http://192.168.0.83:2380,kube-master-03=http://192.168.0.84:2380" ETCD_INITIAL_CLUSTER_STATE="new" ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-for-kubernetes"
- 設定ファイルの書き換え(kube-master-02)
# vi /etc/etcd/etcd.conf
#[Member] ETCD_NAME=kube-master-02 ETCD_DATA_DIR="/var/lib/etcd/default.etcd" ETCD_LISTEN_PEER_URLS="http://192.168.0.83:2380" ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" #[Clustering] ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.0.83:2380" ETCD_ADVERTISE_CLIENT_URLS="http://192.168.0.83:2379" ETCD_INITIAL_CLUSTER="kube-master-01=http://192.168.0.82:2380,kube-master-02=http://192.168.0.83:2380,kube-master-03=http://192.168.0.84:2380" ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-for-kubernetes"
- 設定ファイルの書き換え(kube-master-03)
# vi /etc/etcd/etcd.conf
#[Member] ETCD_NAME=kube-master-03 ETCD_DATA_DIR="/var/lib/etcd/default.etcd" ETCD_LISTEN_PEER_URLS="http://192.168.0.84:2380" ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" #[Clustering] ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.0.84:2380" ETCD_ADVERTISE_CLIENT_URLS="http://192.168.0.84:2379" ETCD_INITIAL_CLUSTER="kube-master-01=http://192.168.0.82:2380,kube-master-02=http://192.168.0.83:2380,kube-master-03=http://192.168.0.84:2380" ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-for-kubernetes"
- サービスの起動と自動起動設定(kube-master-02, kube-master-03)
# systemctl enable etcd # systemctl start etcd
- サービスの起動と自動起動設定(kube-master-01)
# systemctl enable etcd # systemctl start etcd
- クラスタの状態確認(kube-master-01)
# etcdctl member list # etcdctl cluster-health
- コンテナ用ネットワーク設定作成(kube-master-01)
# etcdctl mkdir /ha-kubernetes/network # etcdctl mk /ha-kubernetes/network/config '{ "Network": "10.1.0.0/16", "SubnetLen": 24, "Backend": { "Type": "vxlan" } }'
flannelのインストール - master編 - (kube-master-*)
- wgetのインストール
# yum -y install wget
- バイナリのダウンロード・展開と配置
# mkdir flanneld && cd flanneld # wget https://github.com/coreos/flannel/releases/download/v0.10.0/flannel-v0.10.0-linux-amd64.tar.gz # tar xvzf flannel-v0.10.0-linux-amd64.tar.gz # mv flanneld mk-docker-opts.sh /usr/bin
- ごみ掃除
# cd .. # rm -rf flanneld
- systemdファイル作成
# vi /usr/lib/systemd/system/flanneld.service
[Unit] Description=Flanneld overlay address etcd agent After=network.target After=network-online.target Wants=network-online.target After=etcd.service Before=docker.service [Service] Type=notify EnvironmentFile=/etc/sysconfig/flanneld EnvironmentFile=-/etc/sysconfig/docker-network ExecStart=/usr/bin/flanneld-start $FLANNEL_OPTIONS ExecStartPost=/usr/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker Restart=on-failure [Install] WantedBy=multi-user.target RequiredBy=docker.service
# touch /usr/bin/flanneld-start # chown root:root /usr/bin/flanneld-start # chmod 755 /usr/bin/flanneld-start # vi /usr/bin/flanneld-start
#!/bin/sh exec /usr/bin/flanneld \ -etcd-endpoints=${FLANNEL_ETCD_ENDPOINTS:-${FLANNEL_ETCD}} \ -etcd-prefix=${FLANNEL_ETCD_PREFIX:-${FLANNEL_ETCD_KEY}} \ "$@"
# mkdir /usr/lib/systemd/system/docker.service.d # vi /usr/lib/systemd/system/docker.service.d/flannel.conf
[Service] EnvironmentFile=-/run/flannel/docker
- 設定ファイルの編集
# vi /etc/sysconfig/flanneld
FLANNEL_ETCD_ENDPOINTS="http://127.0.0.1:2379" FLANNEL_ETCD_PREFIX="/ha-kubernetes/network" #FLANNEL_OPTIONS=""
- サービスの起動と自動起動設定
# systemctl enable flanneld # systemctl start flanneld
- dockerサービス再起動
# systemctl restart docker
flannelのインストール - node編 - (kube-node-*)
- wgetのインストール
# yum -y install wget
- バイナリのダウンロード・展開と配置
# mkdir flanneld && cd flanneld # wget https://github.com/coreos/flannel/releases/download/v0.10.0/flannel-v0.10.0-linux-amd64.tar.gz # tar xvzf flannel-v0.10.0-linux-amd64.tar.gz # mv flanneld mk-docker-opts.sh /usr/bin
- ごみ掃除
# cd .. # rm -rf flanneld
- systemdファイル作成
# vi /usr/lib/systemd/system/flanneld.service
[Unit] Description=Flanneld overlay address etcd agent After=network.target After=network-online.target Wants=network-online.target After=etcd.service Before=docker.service [Service] Type=notify EnvironmentFile=/etc/sysconfig/flanneld EnvironmentFile=-/etc/sysconfig/docker-network ExecStart=/usr/bin/flanneld-start $FLANNEL_OPTIONS ExecStartPost=/usr/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker Restart=on-failure [Install] WantedBy=multi-user.target RequiredBy=docker.service
# touch /usr/bin/flanneld-start # chown root:root /usr/bin/flanneld-start # chmod 755 /usr/bin/flanneld-start # vi /usr/bin/flanneld-start
#!/bin/sh exec /usr/bin/flanneld \ -etcd-endpoints=${FLANNEL_ETCD_ENDPOINTS:-${FLANNEL_ETCD}} \ -etcd-prefix=${FLANNEL_ETCD_PREFIX:-${FLANNEL_ETCD_KEY}} \ "$@"
# mkdir /usr/lib/systemd/system/docker.service.d # vi /usr/lib/systemd/system/docker.service.d/flannel.conf
[Service] EnvironmentFile=-/run/flannel/docker
- 設定ファイルの編集
# vi /etc/sysconfig/flanneld
FLANNEL_ETCD_ENDPOINTS="http://192.168.0.89:2379" FLANNEL_ETCD_PREFIX="/ha-kubernetes/network" #FLANNEL_OPTIONS=""
- サービスの起動と自動起動設定
# systemctl enable flanneld # systemctl start flanneld
- dockerサービス再起動
# systemctl restart docker
kubernetesの設定 - master編 - (kube-master-*)
- バイナリのダウンロード
# curl -O https://storage.googleapis.com/kubernetes-release/release/v1.9.1/kubernetes-server-linux-amd64.tar.gz
- tarボールの展開
# tar xvzf kubernetes-server-linux-amd64.tar.gz
- 不要物の削除
# rm -f kubernetes/server/bin/*.*
- バイナリの移動
# mv kubernetes/server/bin/* /usr/bin/
- ゴミ掃除
# rm -rf kubernetes*
- kubeユーザの作成
# groupadd --system kube # useradd \ --home-dir "/home/kube" \ --system \ --shell /bin/false \ -g kube \ kube # mkdir -p /home/kube # chown kube:kube /home/kube
- kubernetes設定ファイル用ディレクトリ作成
# mkdir -p /etc/kubernetes # chown kube:kube /etc/kubernetes
- master用systemdファイル配置
# vi /usr/lib/systemd/system/kube-apiserver.service
[Unit] Description=Kubernetes API Server Documentation=https://github.com/GoogleCloudPlatform/kubernetes After=network.target After=etcd.service [Service] EnvironmentFile=-/etc/kubernetes/config EnvironmentFile=-/etc/kubernetes/apiserver User=kube ExecStart=/usr/bin/kube-apiserver \ $KUBE_LOGTOSTDERR \ $KUBE_LOG_LEVEL \ $KUBE_ETCD_SERVERS \ $KUBE_API_PORT \ $KUBE_API_ADDRESS \ $KUBE_ALLOW_PRIV \ $KUBE_SERVICE_ADDRESSES \ $KUBE_ADMISSION_CONTROL \ $KUBE_API_ARGS Restart=on-failure Type=notify LimitNOFILE=65536 [Install] WantedBy=multi-user.target
# vi /usr/lib/systemd/system/kube-controller-manager.service
[Unit] Description=Kubernetes Controller Manager Documentation=https://github.com/GoogleCloudPlatform/kubernetes [Service] EnvironmentFile=-/etc/kubernetes/config EnvironmentFile=-/etc/kubernetes/controller-manager User=kube ExecStart=/usr/bin/kube-controller-manager \ $KUBE_LOGTOSTDERR \ $KUBE_LOG_LEVEL \ $KUBE_CONTROLLER_MANAGER_ARGS Restart=on-failure LimitNOFILE=65536 [Install] WantedBy=multi-user.target
# vi /usr/lib/systemd/system/kube-scheduler.service
[Unit] Description=Kubernetes Scheduler Plugin Documentation=https://github.com/GoogleCloudPlatform/kubernetes [Service] EnvironmentFile=-/etc/kubernetes/config EnvironmentFile=-/etc/kubernetes/scheduler User=kube ExecStart=/usr/bin/kube-scheduler \ $KUBE_LOGTOSTDERR \ $KUBE_LOG_LEVEL \ $KUBE_SCHEDULER_ARGS Restart=on-failure LimitNOFILE=65536 [Install] WantedBy=multi-user.target
- master用設定ファイル配置
# vi /etc/kubernetes/config
### # kubernetes system config # # The following values are used to configure various aspects of all # kubernetes services, including # # kube-apiserver.service # kube-controller-manager.service # kube-scheduler.service # kubelet.service # kube-proxy.service # logging to stderr means we get it in the systemd journal KUBE_LOGTOSTDERR="--logtostderr=true" # journal message level, 0 is debug KUBE_LOG_LEVEL="--v=0" # Should this cluster be allowed to run privileged docker containers KUBE_ALLOW_PRIV="--allow-privileged=true"
# vi /etc/kubernetes/apiserver
### # kubernetes system config # # The following values are used to configure the kube-apiserver # # The address on the local server to listen to. KUBE_API_ADDRESS="--insecure-bind-address=127.0.0.1 --bind-address=0.0.0.0" # The port on the local server to listen on. KUBE_API_PORT="--insecure-port=8080 --secure-port=6443" # Comma separated list of nodes in the etcd cluster KUBE_ETCD_SERVERS="--etcd-servers=http://127.0.0.1:2379" # Address range to use for services KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=172.16.0.0/16" # default admission control policies KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota" # Add your own! KUBE_API_ARGS="--apiserver-count 3 --cert-dir /etc/kubernetes/certs --basic-auth-file=/etc/kubernetes/basic-auth-list.csv --authorization-mode=ABAC --authorization-policy-file=/etc/kubernetes/abac-policy.json"
# vi /etc/kubernetes/controller-manager
### # The following values are used to configure the kubernetes controller-manager # defaults from config and apiserver should be adequate # Add your own! KUBE_CONTROLLER_MANAGER_ARGS="--kubeconfig=/etc/kubernetes/kubeconfig --service-account-private-key-file=/etc/kubernetes/certs/apiserver.key"
# vi /etc/kubernetes/scheduler
### # kubernetes scheduler config # default config should be adequate # Add your own! KUBE_SCHEDULER_ARGS="--kubeconfig=/etc/kubernetes/kubeconfig"
# vi /etc/kubernetes/kubeconfig
apiVersion: v1 kind: Config clusters: - cluster: server: https://127.0.0.1:6443 insecure-skip-tls-verify: true name: ha-kubernetes contexts: - context: cluster: ha-kubernetes user: kube-process name: kube-process-to-ha-kubernetes current-context: kube-process-to-ha-kubernetes users: - name: kube-process user: username: kube-process password: password
# vi /etc/kubernetes/abac-policy.json
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group":"system:authenticated", "nonResourcePath": "*", "readonly": true}} {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group":"system:unauthenticated", "nonResourcePath": "*", "readonly": true}} {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"admin", "namespace": "*", "resource": "*", "apiGroup": "*" }} {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"kube-process", "namespace": "*", "resource": "*", "apiGroup": "*" }}
# vi /etc/kubernetes/basic-auth-list.csv
password,admin,1 password,kube-process,2
- 設定ファイル権限変更
# chown kube:kube /etc/kubernetes/*
- パスワードファイルセキュリティ対策
# chmod 600 /etc/kubernetes/basic-auth-list.csv
- OpenSSLの設定ファイル「openssl.cnf」のコピー(kube-master-01のみ)
# cd # cp /etc/pki/tls/openssl.cnf .
- openssl.cnfにSANの設定を入れる(kube-master-01のみ)
# sed -i 's/\[ v3_ca \]/\[ v3_ca \]\nsubjectAltName = @alt_names/g' openssl.cnf # cat <<EOF >> openssl.cnf [ alt_names ] DNS.1 = kubernetes.default.svc DNS.2 = kubernetes.default DNS.3 = kubernetes DNS.4 = localhost IP.1 = 192.168.0.89 IP.2 = 172.16.0.1 EOF
- APIサーバ用鍵の作成(kube-master-01のみ)
# openssl genrsa 2048 > apiserver.key
- CSRの作成(kube-master-01のみ)
# openssl req -new -key apiserver.key -out apiserver.csr
# openssl x509 -days 7305 -req -signkey apiserver.key -extensions v3_ca -extfile ./openssl.cnf -in apiserver.csr -out apiserver.crt
- 作成した自己署名証明書と鍵の配置と配布(kube-master-01のみ)
# cp apiserver* /etc/kubernetes/certs # scp apiserver* 192.168.0.83:/etc/kubernetes/certs # scp apiserver* 192.168.0.84:/etc/kubernetes/certs
- パーミッション設定
# chmod 600 /etc/kubernetes/certs/apiserver.key # chown kube:kube /etc/kubernetes/certs/apiserver*
- ごみ掃除(kube-master-01のみ)
# rm -f apiserver.* # rm -f openssl.cnf
- service自動起動設定&起動
# systemctl enable kube-apiserver kube-scheduler kube-controller-manager # systemctl start kube-apiserver # systemctl start kube-scheduler kube-controller-manager
kubernetesの設定 - node編 1 - (kube-master-*)
- swapの無効化
# vi /etc/fstab # reboot
- kubelet用ディレクトリ作成
# mkdir -p /var/lib/kubelet # chown root:root /var/lib/kubelet
- node用systemdファイル配置
# vi /usr/lib/systemd/system/kubelet.service
[Unit] Description=Kubernetes Kubelet Server Documentation=https://github.com/GoogleCloudPlatform/kubernetes After=docker.service Requires=docker.service [Service] WorkingDirectory=/var/lib/kubelet EnvironmentFile=-/etc/kubernetes/config EnvironmentFile=-/etc/kubernetes/kubelet ExecStart=/usr/bin/kubelet \ $KUBE_LOGTOSTDERR \ $KUBE_LOG_LEVEL \ $KUBELET_ADDRESS \ $KUBELET_PORT \ $KUBELET_HOSTNAME \ $KUBE_ALLOW_PRIV \ $KUBELET_POD_INFRA_CONTAINER \ $KUBELET_ARGS Restart=on-failure [Install] WantedBy=multi-user.target
# vi /usr/lib/systemd/system/kube-proxy.service
[Unit] Description=Kubernetes Kube-Proxy Server Documentation=https://github.com/GoogleCloudPlatform/kubernetes After=network.target [Service] EnvironmentFile=-/etc/kubernetes/config EnvironmentFile=-/etc/kubernetes/proxy ExecStart=/usr/bin/kube-proxy \ $KUBE_LOGTOSTDERR \ $KUBE_LOG_LEVEL \ $KUBE_PROXY_ARGS Restart=on-failure LimitNOFILE=65536 [Install] WantedBy=multi-user.target
- node用設定ファイル配置
# vi /etc/kubernetes/kubelet
### # kubernetes kubelet (minion) config # The address for the info server to serve on (set to 0.0.0.0 or "" for all interfaces) KUBELET_ADDRESS="--address=0.0.0.0" # The port for the info server to serve on KUBELET_PORT="--port=10250" # You may leave this blank to use the actual hostname # KUBELET_HOSTNAME="--hostname-override=127.0.0.1" KUBELET_HOSTNAME="" # pod infrastructure container KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=gcr.io/google_containers/pause-amd64:3.0" # Add your own! KUBELET_ARGS="--kubeconfig=/etc/kubernetes/kubeconfig --cgroup-driver=systemd --runtime-cgroups=/systemd/system.slice --kubelet-cgroups=/systemd/system.slice"
# vi /etc/kubernetes/proxy
### # kubernetes proxy config # default config should be adequate # Add your own! KUBE_PROXY_ARGS="--kubeconfig=/etc/kubernetes/kubeconfig --cluster-cidr=172.16.0.0/16"
- 設定ファイル権限変更
# chown kube:kube /etc/kubernetes/*
- service自動起動設定&起動(node)
# systemctl enable kubelet kube-proxy # systemctl start kubelet kube-proxy
kubernetesの設定 - node編 2 - (kube-node-*)
- バイナリのダウンロード
# curl -O https://storage.googleapis.com/kubernetes-release/release/v1.9.1/kubernetes-node-linux-amd64.tar.gz
- tarボールの展開
# tar xvzf kubernetes-node-linux-amd64.tar.gz
- 不要物の削除
# rm -f kubernetes/node/bin/*.*
- バイナリの移動
# mv kubernetes/node/bin/* /usr/bin/
- ゴミ掃除
# rm -rf kubernetes*
- swapの無効化(node)
# vi /etc/fstab # reboot
- kubeユーザの作成
# groupadd --system kube # useradd --home-dir "/home/kube" \ --system \ --shell /bin/false \ -g kube \ kube # mkdir -p /home/kube # chown kube:kube /home/kube
- kubelet用ディレクトリ作成
# mkdir -p /var/lib/kubelet # chown root:root /var/lib/kubelet
- kubernetes設定ファイル用ディレクトリ作成
# mkdir -p /etc/kubernetes # chown kube:kube /etc/kubernetes
- node用systemdファイル配置
# vi /lib/systemd/system/kubelet.service
[Unit] Description=Kubernetes Kubelet Server Documentation=https://github.com/GoogleCloudPlatform/kubernetes After=docker.service Requires=docker.service [Service] WorkingDirectory=/var/lib/kubelet EnvironmentFile=-/etc/kubernetes/config EnvironmentFile=-/etc/kubernetes/kubelet ExecStart=/usr/bin/kubelet \ $KUBE_LOGTOSTDERR \ $KUBE_LOG_LEVEL \ $KUBELET_ADDRESS \ $KUBELET_PORT \ $KUBELET_HOSTNAME \ $KUBE_ALLOW_PRIV \ $KUBELET_POD_INFRA_CONTAINER \ $KUBELET_ARGS Restart=on-failure [Install] WantedBy=multi-user.target
# vi /lib/systemd/system/kube-proxy.service
[Unit] Description=Kubernetes Kube-Proxy Server Documentation=https://github.com/GoogleCloudPlatform/kubernetes After=network.target [Service] EnvironmentFile=-/etc/kubernetes/config EnvironmentFile=-/etc/kubernetes/proxy ExecStart=/usr/bin/kube-proxy \ $KUBE_LOGTOSTDERR \ $KUBE_LOG_LEVEL \ $KUBE_PROXY_ARGS Restart=on-failure LimitNOFILE=65536 [Install] WantedBy=multi-user.target
- node用設定ファイル配置
# vi /etc/kubernetes/config
### # kubernetes system config # # The following values are used to configure various aspects of all # kubernetes services, including # # kube-apiserver.service # kube-controller-manager.service # kube-scheduler.service # kubelet.service # kube-proxy.service # logging to stderr means we get it in the systemd journal KUBE_LOGTOSTDERR="--logtostderr=true" # journal message level, 0 is debug KUBE_LOG_LEVEL="--v=0" # Should this cluster be allowed to run privileged docker containers KUBE_ALLOW_PRIV="--allow-privileged=true"
# vi /etc/kubernetes/kubelet
### # kubernetes kubelet (minion) config # The address for the info server to serve on (set to 0.0.0.0 or "" for all interfaces) KUBELET_ADDRESS="--address=0.0.0.0" # The port for the info server to serve on KUBELET_PORT="--port=10250" # You may leave this blank to use the actual hostname # KUBELET_HOSTNAME="--hostname-override=127.0.0.1" KUBELET_HOSTNAME="" # pod infrastructure container KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=gcr.io/google_containers/pause-amd64:3.0" # Add your own! KUBELET_ARGS="--kubeconfig=/etc/kubernetes/kubeconfig --cgroup-driver=systemd --runtime-cgroups=/systemd/system.slice --kubelet-cgroups=/systemd/system.slice"
# vi /etc/kubernetes/proxy
### # kubernetes proxy config # default config should be adequate # Add your own! KUBE_PROXY_ARGS="--kubeconfig=/etc/kubernetes/kubeconfig --cluster-cidr=172.16.0.0/16"
# vi /etc/kubernetes/kubeconfig
apiVersion: v1 kind: Config clusters: - cluster: server: https://192.168.0.89:6443 insecure-skip-tls-verify: true name: ha-kubernetes contexts: - context: cluster: ha-kubernetes user: kube-process name: kube-process-to-ha-kubernetes current-context: kube-process-to-ha-kubernetes users: - name: kube-process user: username: kube-process password: password
- 設定ファイル権限変更
# chown kube:kube /etc/kubernetes/*
- service自動起動設定&起動
# systemctl enable kubelet kube-proxy # systemctl start kubelet kube-proxy
haproxyをkeepalivedで冗長化して高可用性ロードバランサを構築する
ロードバランサとして活用できるhaproxyですが、ロードバランサ冗長性確保用デーモンであるkeepalivedを使って冗長化してみたので、その手法をメモしておきます。
なんでいきなりhaproxy + keepalivedかというと、Kubernetesの冗長化においてkubeletやkubectlからのkube-apiserverやetcdへのアクセスはMasterノードが複数になるためロードバランスしてやらなくてなりません。ですのでロードバランサが必須になるんですが、単純にロードバランサを追加するだけだとロードバランサ自体がSPOFになってしまうので、ロードバランサ自体の高可用性も勉強してみた、という形です。
構成
構成としては以下の通りとします。
- Webサーバ
- ロードバランサ
- IP: 192.168.0.62, ホスト名: haproxy-01.bbrfkr.mydns.jp
- IP: 192.168.0.63, ホスト名: haproxy-01.bbrfkr.mydns.jp
- VIP: 192.168.0.64
VIP: 192.168.0.64へのHTTPアクセスを背後のhaproxy-01, haproxy-02が受け付け、haproxyはさらに背後のapache-01, apache-02にリクエストを流す、という単純な構成です。
構築手順
- SELinux、firewalldの無効化(haproxy-01, haproxy-02)
検証のため、無効化します。
# sed -i 's/SELINUX=.*/SELINUX=permissive/g' /etc/selinux/config # systemctl disable firewalld # reboot
- haproxy、keepalivedのインストール(haproxy-01, haproxy-02)
# yum -y install haproxy keepalived
- haproxyの設定(haproxy-01, haproxy-02)
# vi /etc/haproxy/haproxy.cfg
frontend main *:80 default_backend web backend web balance roundrobin server web1 192.168.0.60:80 check server web1 192.168.0.61:80 check
- haproxyの起動と自動起動設定(haproxy-01, haproxy-02)
# systemctl enable haproxy # systemctl start haproxy
- keepalivedの設定(haproxy-01)
# vi /etc/keepalived/keepalived.conf
vrrp_script chk_haproxy { script "systemctl is-active haproxy" } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 1 priority 101 virtual_ipaddress { 192.168.0.64 } track_script { chk_haproxy } }
- keepalivedの設定(haproxy-02)
# vi /etc/keepalived/keepalived.conf
vrrp_script chk_haproxy { script "systemctl is-active haproxy" } vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 1 priority 100 virtual_ipaddress { 192.168.0.64 } track_script { chk_haproxy } }
- keepalivedの起動と自動起動設定(haproxy-01, haproxy-02)
# systemctl enable keepalived # systemctl start keepalived
動作確認
構築手順で実施した作業で、haproxy-01にVIP: 192.168.0.64が割り当てられているはずです。
# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:1a:4a:16:02:c7 brd ff:ff:ff:ff:ff:ff inet 192.168.0.62/25 brd 192.168.0.127 scope global eth0 valid_lft forever preferred_lft forever inet 192.168.0.64/32 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::21a:4aff:fe16:2c7/64 scope link valid_lft forever preferred_lft forever
curlで確認しても、VIP: 192.168.0.64に対するリクエストがラウンドロビンでロードバランスされていることが分かるはずです。
# watch -n 0.1 curl 192.168.0.64
この状態で障害を想定し、haproxy-01のサービスhaproxyを停止します。
# systemctl stop haproxy
すると少ししてhaproxy-01からVIPが外れます。
# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:1a:4a:16:02:c7 brd ff:ff:ff:ff:ff:ff inet 192.168.0.62/25 brd 192.168.0.127 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::21a:4aff:fe16:2c7/64 scope link valid_lft forever preferred_lft forever
その後、haproxy-02にVIPが付与されます。(IPフェイルオーバ)
# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:1a:4a:16:02:c8 brd ff:ff:ff:ff:ff:ff inet 192.168.0.63/25 brd 192.168.0.127 scope global eth0 valid_lft forever preferred_lft forever inet 192.168.0.64/32 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::21a:4aff:fe16:2c8/64 scope link valid_lft forever preferred_lft forever
VIP: 192.168.0.64に対するリクエストは引き続き処理できるようになっています。
# watch -n 0.1 curl 192.168.0.64
IPフェイルバックを試してみましょう。haproxy-01のサービスhaproxyを起動します。
# systemctl start haproxy
すると少ししてhaproxy-02からVIPが外れます。
# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:1a:4a:16:02:c8 brd ff:ff:ff:ff:ff:ff inet 192.168.0.63/25 brd 192.168.0.127 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::21a:4aff:fe16:2c8/64 scope link valid_lft forever preferred_lft forever
その後、haproxy-01にVIPが付与されます。(IPフェイルバック)
# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:1a:4a:16:02:c7 brd ff:ff:ff:ff:ff:ff inet 192.168.0.62/25 brd 192.168.0.127 scope global eth0 valid_lft forever preferred_lft forever inet 192.168.0.64/32 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::21a:4aff:fe16:2c7/64 scope link valid_lft forever preferred_lft forever
今更ながらECSを試してみた
Dockerコンテナはこれまで自前でコンテナホストを建てて実行してましたが、パブリッククラウドで使うとどんな使用感なんだろう?と気になり、今更ですがAmazon ECSを使ってみました。今回は簡単にタスクを1個定義して実行してみただけですが、メモとして記事を残しておきます。
◆まずはコンテナ実行環境(クラスタ)を作ります。
◆今回はLinuxでDockerホストを作りますー。
◆クラスタの名前とインスタンスの情報とインスタンスを置くVPCの情報を記載して「作成」をクリック。
◆しばらくするとCloudFormationでコンテナ実行環境ができます。
◆コンテナ実行環境ができたら、次は実行するアプリケーション(タスク)を定義します。その中で実際に実行するコンテナを定義していきます。
◆今回は「irohaboard」というLMSをデプロイします。まずはDBコンテナの定義ですね。環境変数とかも定義できますー。
◆次に本体のirohaboardコンテナの定義です。Dockerのリンク機能で、MariaDBコンテナに接続します。
◆実行コンテナの定義もできたら、「作成」をクリック。
◆クラスタの画面に戻って、「タスク -> 新しいタスクの実行」をクリック。
◆「タスクの実行」をクリックすると、コンテナの準備が始まります。
◆しばらくすると、タスクの状態が「RUNNING」に、コンテナの状態も「RUNNING」になります。
◆irohaboardコンテナの「外部リンク」のURLをクリックすると、出来上がったアプリケーションにアクセスできます。