ビビリフクロウの足跡

とあるインフラSEの勉強&備忘ブログ

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
# 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の最小構成なので、今回はDashboardDNSサービスをデプロイしたいと思います。 まずは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自体のベーシック認証を有効化する
      • オプション指定
...
    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設定

  • kubeletにkube-dnsサービスのIPと管理ドメインを設定する(kube-*)
# 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
  • manifestを修正して、以下を設定
# 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

これでDashboardDNSサービス用のPodなりServiceなりが正常に上がるはずです。

Dashboardはこんな感じ。

f:id:bbrfkr:20180325202055p:plain

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を挟むことによってマスターの冗長化を実現しています。

f:id:bbrfkr:20180318233148p:plain

なお、利用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

検証のため、無効化します。

# 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
# 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
    }
}
# 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
    }
}
# 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
# 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
# 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
# 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
# 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
# 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/*
# 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
# mkdir -p /var/lib/kubelet
# chown root:root /var/lib/kubelet
# 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/*
# 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.60, ホスト名: apache-01.bbrfkr.mydns.jp
    • IP: 192.168.0.61, ホスト名: apache-02.bbrfkr.mydns.jp
  • ロードバランサ
    • 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
# 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
    }
}
# 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
    }
}
# 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個定義して実行してみただけですが、メモとして記事を残しておきます。

◆まずはコンテナ実行環境(クラスタ)を作ります。 f:id:bbrfkr:20180312221801p:plain

◆今回はLinuxでDockerホストを作りますー。 f:id:bbrfkr:20180312221851p:plain

クラスタの名前とインスタンスの情報とインスタンスを置くVPCの情報を記載して「作成」をクリック。 f:id:bbrfkr:20180312221920p:plain f:id:bbrfkr:20180312222041p:plain f:id:bbrfkr:20180312222121p:plain

◆しばらくするとCloudFormationでコンテナ実行環境ができます。 f:id:bbrfkr:20180312222304p:plain

◆コンテナ実行環境ができたら、次は実行するアプリケーション(タスク)を定義します。その中で実際に実行するコンテナを定義していきます。 f:id:bbrfkr:20180312222351p:plain f:id:bbrfkr:20180312222540p:plain f:id:bbrfkr:20180312222554p:plain

◆今回は「irohaboard」というLMSをデプロイします。まずはDBコンテナの定義ですね。環境変数とかも定義できますー。 f:id:bbrfkr:20180312222507p:plain f:id:bbrfkr:20180312222526p:plain

◆次に本体のirohaboardコンテナの定義です。Dockerのリンク機能で、MariaDBコンテナに接続します。 f:id:bbrfkr:20180312222715p:plain f:id:bbrfkr:20180312222725p:plain

◆実行コンテナの定義もできたら、「作成」をクリック。 f:id:bbrfkr:20180312222751p:plain

クラスタの画面に戻って、「タスク -> 新しいタスクの実行」をクリック。 f:id:bbrfkr:20180312222850p:plain f:id:bbrfkr:20180312222902p:plain

◆「タスクの実行」をクリックすると、コンテナの準備が始まります。 f:id:bbrfkr:20180312222946p:plain

◆しばらくすると、タスクの状態が「RUNNING」に、コンテナの状態も「RUNNING」になります。 f:id:bbrfkr:20180312223025p:plain f:id:bbrfkr:20180312223126p:plain

◆irohaboardコンテナの「外部リンク」のURLをクリックすると、出来上がったアプリケーションにアクセスできます。 f:id:bbrfkr:20180313210517p:plain f:id:bbrfkr:20180312223221p:plain

rktをインストールしてコンテナを起動してみた

巷でコンテナランタイムといえばまだまだDockerが有名ですが、他にもrkt、containerd、LXD、cri-oなど、いろいろあります。今回はrktをDebian 9にインストールしてコンテナを上げてみたのでその手順をメモメモです。

  • sidを登録
$ sudo vi /etc/apt/sources.list
...
deb http://ftp.jp.debian.org/debian/ sid main non-free contrib
deb-src http://ftp.jp.debian.org/debian/ sid main non-free contrib
  • rktのインストール
$ sudo apt-get update
$ sudo apt-get install rkt
  • Docker Hubのnginxイメージ取得
$ sudo rkt fetch --insecure-options=image docker://nginx:latest
  • nginxコンテナの起動(host port 8080番に暴露)
$ sudo rkt run --port=80-tcp:8080 registry-1.docker.io/library/nginx:latest

この状態でホストの8080番ポートに対してcurlするとnginxのおなじみのデフォルトページが返ってくるはずです。

$ curl localhost:8080