2020-11-06 12:52 PM 2021-03-05 05:16 PM 更新
ACIは特定の仮想化基盤やコンテナ基盤に依存したソリューションではありませんが、逆に言えば幅広いコンピューティングリソースに対して、それらの対象と連携してACIを利用頂くことも、逆に一切連携せずに単にNetwork FabricとしてACIを利用頂くことも、どちらも可能です。Kubernetesに対しても、ACIはACI CNIを提供することでネイティブな連携が可能となっています。サポートされるバージョンの組み合わせ等の最新情報については、互換性マトリックスを参照ください。
https://www.cisco.com/c/dam/en/us/td/docs/Website/datacenter/aci/virtualization/matrix/virtmatrix.html
オフィシャルなACI - Kubernetesの連携については、以下のTech Notesを参照下さい。本ページの情報は、以下URL記載の情報の補足としてご利用下さい。手順や指定に差異がある場合には、Tech Notesを優先して下さい。
https://www.cisco.com/c/en/us/td/docs/switches/datacenter/aci/apic/sw/kb/b_Kubernetes_Integration_with_ACI.html
また、英語でのご説明となりますが、以下のYouTube動画でACI - Kubernetes連携構成の概要や構成手順について詳細に解説・実際の構成録画が公開されています。本ページの情報と合わせて参考下さい。また、本ページでは動画3/3で解説されている、Multi-Site構成での利用に関しては含めていません。Multi-Site構成でのACI - Kubernetes連携を構成される方は、以下動画を参考下さい。
本ページでは、基本的な手順としてKubernetesを構成しACI CNIを組み込む手順を説明しています。Kubernetesの構成方法はkubeadmを用いる方法以外にも多数ありますし、各社からより簡易な方法が提供されているソリューションもあります。それらを使用する場合には、適宜読み替えて判断してください。
ACIとKubernetesの連携は、Kubernetesがネットワークと連携するための標準化された仕組みであるCNIを用いて実装されているため、Kubernetesを利用するアプリケーションエンジニア側からはACIの存在を意識することなくKubernetesを利用頂くことが可能です。同時に、インフラリソースの管理者側からはKubernetes側のステータスを把握できるようになるとともに、必要に応じてACIのEPGおよびContractを用いたセキュリティルールの強制を行うなどのガバナンス管理を物理サーバや仮想マシンなどを利用する場合と同様に適用することができます。
本ページでは、以下の準備と構成は完了していることを前提としています。
ACIをKubernetesに連携するには、以下の手順での構成を行います。
■01.Kubernetesクラスタパラメータの決定
Kubernetes環境を構成するために必要となる以下のパラメータを決定します。
パラメータ項目 | 本例でのパラメータ例 | 補足 |
ACI Tenant 名 | tsetaka_k8s | 未指定の場合は common テナントが使用される。 |
ACI L3out 名 | l3out_k8s | |
ACI L3out - External EPG 名 | ext_all | |
使用するMulticast IPレンジ | 225.17.1.1〜225.17.1.255 | ACI Fabric範囲において、他のKubernetes連携やAVE/AVS連携などで使用していないレンジの指定が必要(重複利用不可)。 |
使用するVMM Domain | vc_pod2 | KubuernetesノードにVMを利用する場合のみ必要。 |
system_id | tsetaka_lab_k8s | ACI Fabric範囲において、他のKubernetes連携で使用していないIDの指定が必要。 |
node_subnet | 10.101.0.1/16 | 全Kubernetesノードに対して構成するIPアドレスのSubnet範囲と合わせる。指定したIPアドレスがBD SubnetのGWとなる。 |
pod_subnet | 10.102.0.1/16 | Podに対して払い出されるIPアドレス範囲。指定したIPアドレスがBD SubnetのGWとなる。/16の指定を推奨。 |
extern_dynamic | 10.103.0.1/24 | Deploymentに対してExternal IPを構成する際に動的に払い出されるIPアドレス範囲。 |
extern_static | 10.104.0.1/24 | Deploymentに対してExternal IPを構成する際に静的に指定する場合に利用するIPアドレス範囲。 |
node_svc_subnet | 10.105.0.1/24 | Deploymentに対して払い出されるCluster IPアドレス範囲。 |
cluster_svc_subnet | 10.106.0.0/16 | kubeadmでKubernetes環境を展開する際に "--service-cidr=" で指定するIPアドレス範囲。 |
kubeapi_vlan | 600 | AEP範囲で他用途に利用していないVLANを推奨。 |
service_vlan | 601 | AEP範囲で他用途に利用していないVLANを推奨。 |
infra_vlan | 3967 | ACI初期構成時に指定したInfra VLANを指定する。 |
■02.必要となるACI側の事前準備
ACI CNIを用いたKubernetes連携を構成する前に、ACI側では以下の構成を事前に済ませておく必要があります。また、これらの項目は、後ほど作成するACI構成用のyamlファイルの中で正しく同じ名前を指定する必要があります。
■03.acc-provisionのインストールと構成ファイルの作成
cisco.com のダウンロードサイトから、ACI CNI Tools をダウンロードします。Debian用とRPM用の2種類が提供されています。Ubuntuの場合は、Debian用を利用します。本ページの説明では、Release 5.0(2.20200831)を使用したため、ACI CNI Toolsとしては "dist-debs-5.0.2.2.tar.gz" を使用します。
https://software.cisco.com/download/home/285968390/type/286304714/release/5.0(2.20200831)
ダウンロードしたファイルを解凍し、acc-provision_5.0.2.0-28_amd64.deb ファイルを対象とし、aptを使って必要とするパッケージと共にインストールします(RPMの場合は、別途yum等を利用したローカルインストールに読み替えて下さい)。
root@tsmgmt:~/aci-k8s-5.0# apt install ./acc-provision_5.0.2.0-28_amd64.deb Reading package lists... Done Building dependency tree Reading state information... Done Note, selecting 'acc-provision' instead of './acc-provision_5.0.2.0-28_amd64.deb' The following additional packages will be installed: python-ipaddr The following NEW packages will be installed: python-ipaddr The following packages will be upgraded: acc-provision 1 upgraded, 1 newly installed, 0 to remove and 358 not upgraded. Need to get 14.9 kB/9,937 kB of archives. After this operation, 12.1 MB of additional disk space will be used. Do you want to continue? [Y/n] Y Get:1 /root/aci-k8s-5.0/acc-provision_5.0.2.0-28_amd64.deb acc-provision amd64 5.0.2.0-28 [9,922 kB] Get:2 http://jp.archive.ubuntu.com/ubuntu xenial/main amd64 python-ipaddr all 2.1.11-2 [14.9 kB] Fetched 14.9 kB in 30s (494 B/s) Selecting previously unselected package python-ipaddr. (Reading database ... 181667 files and directories currently installed.) Preparing to unpack .../python-ipaddr_2.1.11-2_all.deb ... Unpacking python-ipaddr (2.1.11-2) ... Preparing to unpack .../acc-provision_5.0.2.0-28_amd64.deb ... Unpacking acc-provision (5.0.2.0-28) over (4.1.1.2-13) ... Setting up python-ipaddr (2.1.11-2) ... Setting up acc-provision (5.0.2.0-28) ... N: Can't drop privileges for downloading as file '/root/aci-k8s-5.0/acc-provision_5.0.2.0-28_amd64.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied) root@tsmgmt:~/aci-k8s-5.0# root@tsmgmt:~/aci-k8s-5.0# acc-provision -v 5.0.2.0インストールしたacc-provisionツールを利用して、ACIを構成するためのyamlファイルのサンプルファイル(以下例では "k8s01.yaml")を生成します。
acc-provision --flavor=kubernetes-1.17 --sample > k8s01.yaml
これにより、ACI構成用のyamlファイルのサンプルファイルが実行フォルダに生成されます。このファイルを元に、環境とパラメータに合わせてファイルを修正します。
yamlファイルですので、改行のインデントには注意して下さい。
※以下のサンプルでは、コメント行などを一部削除しています。また、一部パラメータを実際とは書き換えています。
# # Configuration for ACI Fabric # aci_config: tenant: name: tsetaka_k8s system_id: tsetaka_lab_k8s # Every opflex cluster must have a distinct ID #apic-refreshtime: 1200 # Subscrption refresh-interval in seconds; Max=43200 apic_hosts: # List of APIC hosts to connect for APIC API - 172.16.1.1 - 172.16.1.2 - 172.16.1.3 vmm_domain: # Kubernetes container domain configuration encap_type: vxlan # Encap mode: vxlan or vlan mcast_range: # Every opflex VMM must use a distinct range start: 225.17.1.1 end: 225.17.1.254 nested_inside: # Include if nested inside a VMM; type: vmware # Specify the VMM vendor (supported: vmware) name: vc_pod2 # Specify the name of the VMM domain # The following resources must already exist on the APIC. # They are used, but not created, by the provisioning tool. aep: ACILAB_Standard_AAEP # The AEP for ports/VPCs used by this cluster vrf: # This VRF used to create all kubernetes EPs name: vrf_k8s tenant: tsetaka_k8s # This can be system-id or common l3out: name: l3out_k8s # Used to provision external IPs external_networks: - ext_all # Used for external contracts # # Networks used by ACI containers # net_config: node_subnet: 10.101.0.1/16 # Subnet to use for nodes pod_subnet: 10.102.0.1/16 # Subnet to use for Kubernetes # Pods/CloudFoundry containers extern_dynamic: 10.103.0.1/24 # Subnet to use for dynamic external IPs extern_static: 10.104.0.1/24 # Subnet to use for static external IPs node_svc_subnet: 10.105.0.1/24 # Subnet to use for service graph kubeapi_vlan: 600 # The VLAN used by the physdom for nodes # (Kubernetes only) service_vlan: 601 # The VLAN used by LoadBalancer services infra_vlan: 3967 # The VLAN used by ACI infra interface_mtu: 8900 # min = 1280 for ipv6, max = 8900 for VXLAN service_monitor_interval: 5 # IPSLA interval probe time for PBR tracking # default is 5, set to 0 to disable, max: 65535 pbr_tracking_non_snat: true # Default is false, set to true for IPSLA to # be effective with non-snat services # # Configuration for container registry # Update if a custom container registry has been setup # registry: image_prefix: noiro # e.g: registry.example.com/noiro # image_pull_secret: secret_name # (if needed) #kube_config: # ovs_memory_limit: "20Gi" # override if needed, default is "1Gi" # reboot_opflex_with_ovs: "false" # override if needed, default is "true" #istio_config: # install_istio: False # default is True # install_profile: "default" # override if needed, default is "demo" #drop_log_config: # enable: False # default is True
■04.ACIの構成とCNIプラグイン構成ファイルの生成
続いて、acc-provisionツールを利用し、準備したACIの構成を行うためのyamlファイル(以下の例では "k8s01.yaml")を使って、CNIプラグインを構成するためのyamlファイル(以下の例では "aci-cni-config.yaml")を生成するとともに、Kubernetesを連携するACI環境に対して構成を行います。
※以下のサンプルでは、一部パラメータを実際とは書き換えています。
aci@k8s117a:~/k8s01$ sudo acc-provision --flavor=kubernetes-1.17 -a -u admin -p password -c k8s01.yaml -o aci-cni-config.yaml INFO: Loading configuration from "k8s01.yaml" INFO: Using configuration flavor kubernetes-1.17 INFO: Generating certs for kubernetes controller INFO: Private key file: "user-tsetaka_lab_k8s.key" INFO: Certificate file: "user-tsetaka_lab_k8s.crt" INFO: Writing kubernetes infrastructure YAML to aci-cni-config.yaml INFO: Writing ACI CNI operator tar to aci-cni-config.yaml.tar.gz INFO: Apply infrastructure YAML using: INFO: kubectl apply -f aci-cni-config.yaml INFO: Delete stale objects from older deployments using: INFO: kubectl -n aci-containers-system delete configmap,secret,serviceaccount,daemonset,deployment,clusterrolebinding,clusterrole -l 'aci-containers-config-version,aci-containers-config-version notin (4bb7517f-1cd6-4790-afd4-3fadf707b64e)' INFO: Provisioning configuration in APIC
WARNやERRORなどなく、構成が完了することを確認して下さい。構成に失敗する場合や、エラーが発生する場合は、準備したyamlファイルに間違いがないかを確認して下さい。
上記操作により、ACI側に以下が指定パラメータに合わせて自動的に構成されます。
必要に応じて、Kubernetesノードの接続に利用しているInterface Policy Groupに対してAEPを適切に紐付けるなど、追加で手動での構成が必要となる場合があります。
■05.Linux環境の構成(ホスト名、Swapの無効化、ネットワークなど)
Kubernetes用Linuxでは、以下の要件を満たす必要があります。
Swapは無効化することが推奨です。
swapoff -a
/etc/fstab において、swapに関する行をコメントアウトしてスワップファイルもしくはスワップ領域の利用を無効化して下さい。
# /etc/fstab: static file system information. # # Use 'blkid' to print the universally unique identifier for a # device; this may be used with UUID= as a more robust way to name devices # that works even if disks are added and removed. See fstab(5). # # <file system> <mount point> <type> <options> <dump> <pass> # / was on /dev/ubuntu-vg/ubuntu-lv during curtin installation /dev/disk/by-id/dm-uuid-LVM-mzxn81t4YIWnQXBw93olnjWyqX2qylw5abP5L1fpolEK4fUZLSsnnDncFMWih42f / ext4 defaults 0 0 # /boot was on /dev/sda2 during curtin installation /dev/disk/by-uuid/3415aa00-9d22-4d77-8fe9-3c188b461010 /boot ext4 defaults 0 0 #/swap.img none swap sw 0 0
Ubuntu 18.04 利用時に置いて、以降で実施するKubernetesにおいてcertificates関連の問題が発生する場合には、以下のように timedatectl の無効化と NTP サービスの適切な構成を行って下さい。
sudo timedatectl set-ntp no sudo apt-get install ntp sudo systemctl start ntp sudo systemctl enable ntp
kubeapi_vlan で指定したVLANと同じVLANのVLANインターフェイスを構成し、定義ファイルに基づいてACI側に作成されたBDに構成されたGWにデフォルトGWを向けて下さい。この際、Default GWまでのPing疎通を確認して下さい。ここで問題がある場合には、以下の手順に進む前に問題を解決して下さい。
以下の例では、kubeapi_vlan として VLAN 600 を、インターフェイスとして ens192 を利用する場合の例となります。この例では、別Interface ens160 を固定IPで利用していますが、こちらにはDefault GWは構成していません。
ACI Leaf接続側のインターフェイスのMACアドレスを確認しコピーします(以下例では、ens190に割り当てられている "00:50:56:b8:bc:f3")。
※以下のサンプルでは、一部パラメータを実際とは書き換えています。
aci@k8s117a:~$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 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: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 00:50:56:b8:c8:f7 brd ff:ff:ff:ff:ff:ff inet 172.16.1.15/24 brd 172.16.1.255 scope global ens160 valid_lft forever preferred_lft forever inet6 fe80::250:56ff:feb8:c8f7/64 scope link valid_lft forever preferred_lft forever 3: ens192: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 00:50:56:b8:bc:f3 brd ff:ff:ff:ff:ff:ff aci@k8s117a:~$
以下では、Ubuntu 18 で netplan を利用する場合の例となります(以下では、/etc/netplan/ 配下のファイルを削除し、"01-netcfg.yaml" という名称で構成ファイルを作成した例となります)。
netplanを利用しない場合や、Red Hat系Linuxを利用している場合は、適宜読み替えて下さい。
kubeapi_vlan のVLANインターフェイスに、指定したSubnet範囲内のIPアドレスとDefault GW、適切なDNSサーバの指定を行います。また、infra_vlan のVLANインターフェイスはDHCP構成とし、Multicast用のRouteを構成します。
※以下のサンプルでは、一部パラメータを実際とは書き換えています。yamlファイルですので、改行のインデントには注意して下さい。
aci@k8s17p2e:/etc/netplan$ cat 01-netcfg.yaml network: ethernets: ens160: #dhcp4: true dhcp4: false addresses: [172.16.1.15/24] ens192: match: macaddress: 00:50:56:b8:bc:f3 set-name: ens192 dhcp4: false dhcp6: false mtu: 9000 vlans: vlan.600: id: 600 link: ens192 dhcp4: false dhcp6: false addresses: [10.101.0.145/16] gateway4: 10.101.0.1 nameservers: addresses: [10.123.123.123] vlan.3967: id: 3967 link: ens192 dhcp4: true routes: - scope: link to: 224.0.0.0/4 version: 2 aci@k8s17p2e:/etc/netplan$
infra_vlan 用のインターフェイスでAPICからのDHCPによるIPアドレスの払い出しを適切に動作させるために、/etc/dhcp/dhclient.conf ファイルを以下のように適切に構成します。
なお、環境毎に1行目の "send dhcp-client-identifier 01:" 以降に ACI Leaf 接続側インターフェイスのMACアドレスを設定して下さい。頭の 01 は消さないで下さい。
send dhcp-client-identifier 01:00:50:56:b8:bc:f3; request subnet-mask, domain-name, domain-name-servers, host-name; send host-name = gethostname(); option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; option ms-classless-static-routes code 249 = array of unsigned integer 8; option wpad code 252 = string; also request rfc3442-classless-static-routes; also request ms-classless-static-routes; also request static-routes; also request wpad; also request ntp-servers; timeout 30;
ここまで構成を行ったら、IPアドレスの適用を実施し、以下の点について確認を実施して下さい。
aci@k8s117a:~$ sudo netplan apply aci@k8s117a:~$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 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: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 00:50:56:b8:c8:f7 brd ff:ff:ff:ff:ff:ff inet 172.16.1.15/16 brd 172.16.1.255 scope global ens160 valid_lft forever preferred_lft forever inet6 fe80::250:56ff:feb8:c8f7/64 scope link valid_lft forever preferred_lft forever 3: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc mq state UP group default qlen 1000 link/ether 00:50:56:b8:bc:f3 brd ff:ff:ff:ff:ff:ff inet6 fe80::250:56ff:feb8:bcf3/64 scope link valid_lft forever preferred_lft forever 4: vlan.600@ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue state UP group default qlen 1000 link/ether 00:50:56:b8:bc:f3 brd ff:ff:ff:ff:ff:ff inet 10.101.0.145/16 brd 10.101.255.255 scope global vlan.600 valid_lft forever preferred_lft forever inet6 fe80::250:56ff:feb8:bcf3/64 scope link valid_lft forever preferred_lft forever 5: vlan.3967@ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue state UP group default qlen 1000 link/ether 00:50:56:b8:bc:f3 brd ff:ff:ff:ff:ff:ff inet 10.1.24.65/16 brd 10.1.255.255 scope global dynamic vlan.3967 valid_lft 604798sec preferred_lft 604798sec inet6 fe80::250:56ff:feb8:bcf3/64 scope link valid_lft forever preferred_lft forever aci@k8s117a:~$
EPG "aci-containers-nodes" に各KubernetesノードのMACアドレスおよびIPアドレスがPhysical Domain に紐付いて認識されます。
■06.Dockerのインストール
※以下の作業では、インターネットへの接続環境を前提としています。KubernetesノードはACI Leaf接続側にDefault GWを向けていますので、当該VRFに対して構成したL3out経由でインターネットへ接続できる構成が必要となります。Proxyの指定が必要となる環境の場合は、別途適切にProxy関連の設定を行って下さい。なお、Proxyを構成する場合には、逆にProxy除外するネットワーク範囲についても適切に指定して下さい(Kubernetes環境で利用するSubnet範囲などはProxyを利用しないように構成してください)。
Dockerの構成手順については、基本的にKubernetes公式サイトにある以下の手順に従って構成してください。
https://kubernetes.io/docs/setup/production-environment/container-runtimes/
sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common gnupg2 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 add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
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 \ containerd.io=1.2.13-2 \ docker-ce=5:19.03.11~3-0~ubuntu-$(lsb_release -cs) \ docker-ce-cli=5:19.03.11~3-0~ubuntu-$(lsb_release -cs)
cat > /etc/docker/daemon.json <<EOF { "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2" } EOF mkdir -p /etc/systemd/system/docker.service.d
■07.Kubernetesのインストール
Kubernetesのインストールにおいては、ACIがサポートするバージョンのKubernetesを利用して下さい。パッチレベルについてはACIのCompatibilityでは規定していないため、基本的には最新パッチリリースを利用して下さい。ACI 5.1以降では Kubernetes 1.18 がサポートされましたが、本ページの解説に利用している環境では、ACI 5.0 で構成を実施したため、Kubernetes 1.17 を指定しています。
前提として必要となるソフトウェアのインストールを行います。
sudo apt-get update && sudo apt-get install -y apt-transport-https curl
Kubernetesのレポジトリで利用される証明書を取得します。
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
Kubernetesのレポジトリを構成します。
sudo cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main EOF
apt-getでレポジトリを更新します。
sudo apt-get update
インストールしたいKubernetesバージョンの最新リリースを確認します。
sudo apt-cache show kubeadm | grep Version | grep 1.17
Kubernetesリリースを指定してインストールを行います(以下の例では1.17.13を指定)。また、インストール後にバージョンの固定を行うことで、意図しないアップグレードを防止できます。
sudo apt install kubelet=1.17.13-00 kubectl=1.17.13-00 kubeadm=1.17.13-00 sudo apt-mark hold kubelet kubeadm kubectl
■08.Control Plane NodeのHA構成
Control PlaneのHA化についてはいくつかの方法がありますが、ここではkeepalivedとhaproxyを用いた方法を掲載します。基本的には、以下のURL掲載の手順を実施します。
https://github.com/kubernetes/kubeadm/blob/master/docs/ha-considerations.md#options-for-software-load-balancing
必要なソフトウェアをインストールします
sudo apt-get install haproxy keepalived
keepalivedの構成:/etc/keepalived/keepalived.conf
以下の例では、10.101.0.0/16が kubeapi_vlan のSubnetであり、Control Plane Node で共有する Virtual IP アドレスとして 10.101.0.101 を利用する場合となります。
★プライマリノード
! /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { router_id LVS_DEVEL } vrrp_script check_apiserver { script "/etc/keepalived/check_apiserver.sh" interval 3 weight -2 fall 10 rise 2 } vrrp_instance VI_1 { state MASTER interface vlan.600 virtual_router_id 51 priority 101 authentication { auth_type PASS auth_pass Admin1234! } virtual_ipaddress { 10.101.0.101 } track_script { check_apiserver } }
★セカンダリノード
! /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { router_id LVS_DEVEL } vrrp_script check_apiserver { script "/etc/keepalived/check_apiserver.sh" interval 3 weight -2 fall 10 rise 2 } vrrp_instance VI_1 { state SLAVE interface vlan.600 virtual_router_id 51 priority 100 authentication { auth_type PASS auth_pass Admin1234! } virtual_ipaddress { 10.101.0.101 } track_script { check_apiserver } }
ステータスチェック用のスクリプトファイルを作成します(/etc/keepalived/check_apiserver.sh)。
#!/bin/sh errorExit() { echo "*** $*" 1>&2 exit 1 } _ curl --silent --max-time 2 --insecure https://localhost:8443/ -o /dev/null || errorExit "Error GET https://localhost:8443/" if ip addr | grep -q 10.101.0.101; then curl --silent --max-time 2 --insecure https://10.101.0.101:8443/ -o /dev/null || errorExit "Error GET https://10.101.0.101:8443/" fi
続いて、HAProxyの構成ファイル(/etc/haproxy/haproxy.cfg)を構成します。こちらは全Control Plane Node共通となります。本例では、HAを構成するノードは2台で、各ノードのIPアドレスは 10.101.0.145 および 10.101.0.146 の場合となります。
# /etc/haproxy/haproxy.cfg #--------------------------------------------------------------------- # Global settings #--------------------------------------------------------------------- global log /dev/log local0 log /dev/log local1 notice daemon #--------------------------------------------------------------------- # common defaults that all the 'listen' and 'backend' sections will # use if not designated in their block #--------------------------------------------------------------------- defaults mode http log global option httplog option dontlognull option http-server-close option forwardfor except 127.0.0.0/8 option redispatch retries 1 timeout http-request 10s timeout queue 20s timeout connect 5s timeout client 300s timeout server 300s timeout http-keep-alive 10s timeout check 10s #--------------------------------------------------------------------- # apiserver frontend which proxys to the masters #--------------------------------------------------------------------- frontend apiserver bind *:8443 mode tcp option tcplog default_backend apiserver #--------------------------------------------------------------------- # round robin balancing for apiserver #--------------------------------------------------------------------- backend apiserver option httpchk GET /healthz http-check expect status 200 mode tcp option ssl-hello-chk balance roundrobin server k8s17p2a 10.101.0.145:6443 check server k8s17p2b 10.101.0.146:6443 check
最後に、サービスの起動と有効化を定義します。この時点では、Kubernetesが動作していないためHAProxyではエラーが出ますが、問題ありません。プライマリノード側にVirtual IPが追加構成されることを確認して下さい。
sudo systemctl start keepalived sudo systemctl restart haproxy sudo systemctl enable keepalived sudo systemctl enable haproxy
■09.Kubernetesの構成(kubeadm)
kubeadm コマンドを使って、Kubernetesの構成を行います。
aci@k8s117a:/$ sudo kubeadm init --pod-network-cidr=10.102.0.1/16 --service-cidr=10.106.0.1/16 --control-plane-endpoint 10.101.0.101:8443 --upload-certs I1026 06:44:56.489063 9413 version.go:251] remote version is much newer: v1.19.3; falling back to: stable-1.17 W1026 06:44:58.022782 9413 validation.go:28] Cannot validate kube-proxy config - no validator is available W1026 06:44:58.023134 9413 validation.go:28] Cannot validate kubelet config - no validator is available [init] Using Kubernetes version: v1.17.13 [preflight] Running pre-flight checks [preflight] Pulling images required for setting up a Kubernetes cluster [preflight] This might take a minute or two, depending on the speed of your internet connection [preflight] You can also perform this action in beforehand using 'kubeadm config images pull' [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Starting the kubelet [certs] Using certificateDir folder "/etc/kubernetes/pki" [certs] Generating "ca" certificate and key [certs] Generating "apiserver" certificate and key [certs] apiserver serving cert is signed for DNS names [k8s117a kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.106.0.1 10.101.0.145 10.101.0.101] [certs] Generating "apiserver-kubelet-client" certificate and key [certs] Generating "front-proxy-ca" certificate and key [certs] Generating "front-proxy-client" certificate and key [certs] Generating "etcd/ca" certificate and key [certs] Generating "etcd/server" certificate and key [certs] etcd/server serving cert is signed for DNS names [k8s117a localhost] and IPs [10.101.0.145 127.0.0.1 ::1] [certs] Generating "etcd/peer" certificate and key [certs] etcd/peer serving cert is signed for DNS names [k8s117a localhost] and IPs [10.101.0.145 127.0.0.1 ::1] [certs] Generating "etcd/healthcheck-client" certificate and key [certs] Generating "apiserver-etcd-client" certificate and key [certs] Generating "sa" key and public key [kubeconfig] Using kubeconfig folder "/etc/kubernetes" [endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address [kubeconfig] Writing "admin.conf" kubeconfig file [endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address [kubeconfig] Writing "kubelet.conf" kubeconfig file [endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address [kubeconfig] Writing "controller-manager.conf" kubeconfig file [endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address [kubeconfig] Writing "scheduler.conf" kubeconfig file [control-plane] Using manifest folder "/etc/kubernetes/manifests" [control-plane] Creating static Pod manifest for "kube-apiserver" [control-plane] Creating static Pod manifest for "kube-controller-manager" W1026 06:57:11.020477 9413 manifests.go:214] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC" [control-plane] Creating static Pod manifest for "kube-scheduler" W1026 06:57:11.023188 9413 manifests.go:214] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC" [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests" [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s [apiclient] All control plane components are healthy after 36.517230 seconds [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-1.17" in namespace kube-system with the configuration for the kubelets in the cluster [upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace [upload-certs] Using certificate key: 059720c80e7661e7a7a4ad61e26f9882069ce17a23725d5998ec6aec45f678f6 [mark-control-plane] Marking the node k8s117a as control-plane by adding the label "node-role.kubernetes.io/master=''" [mark-control-plane] Marking the node k8s117a as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] [bootstrap-token] Using token: n7ygyk.z3r8pcil0acu6elz [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials [bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token [bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster [bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace [kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key [addons] Applied essential addon: CoreDNS [endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address [addons] Applied essential addon: kube-proxy 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 the control-plane node running the following command on each as root: kubeadm join 10.101.0.101:8443 --token n7ygyk.z3r8pcil0acu6elz \ --discovery-token-ca-cert-hash sha256:dda480a449b5d8ba8c134c0f5ef38af3d26a49fe999f822305b8e0778b127455 \ --control-plane --certificate-key 059720c80e7661e7a7a4ad61e26f9882069ce17a23725d5998ec6aec45f678f6 Please note that the certificate-key gives access to cluster sensitive data, keep it secret! As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use "kubeadm init phase upload-certs --upload-certs" to reload certs afterward. Then you can join any number of worker nodes by running the following on each as root: kubeadm join 10.101.0.101:8443 --token n7ygyk.z3r8pcil0acu6elz \ --discovery-token-ca-cert-hash sha256:dda480a449b5d8ba8c134c0f5ef38af3d26a49fe999f822305b8e0778b127455 aci@k8s117a:/$
2台目のControl Plane NodeはControl Plane Node用の、その他Worker NodeはWorker Node用の実行コマンドをコピーして利用し、Kubernetesクラスタに参加させて下さい。
★2台目 Control Plane Nodeの構成
kubeadm join 10.101.0.101:8443 --token n7ygyk.z3r8pcil0acu6elz \ --discovery-token-ca-cert-hash sha256:dda480a449b5d8ba8c134c0f5ef38af3d26a49fe999f822305b8e0778b127455 \ --control-plane --certificate-key 059720c80e7661e7a7a4ad61e26f9882069ce17a23725d5998ec6aec45f678f6
★Worker Nodeの構成
kubeadm join 10.101.0.101:8443 --token n7ygyk.z3r8pcil0acu6elz \ --discovery-token-ca-cert-hash sha256:dda480a449b5d8ba8c134c0f5ef38af3d26a49fe999f822305b8e0778b127455
最終的に本例の構成では、2台のControl Plane Node (k8s117a, k8s117b)と、3台のWorker Node (k8s117c, k8s117d, k8s117e)を構成しました。[kubectl get nodes]コマンドでKubernetesクラスタのノード状態を確認して下さい。
aci@k8s117a:/$ kubectl get nodes NAME STATUS ROLES AGE VERSION k8s117a NotReady master 22m v1.17.13 k8s117b NotReady master 7m25s v1.17.13 k8s117c NotReady <none> 2m58s v1.17.13 k8s117d NotReady <none> 48s v1.17.13 k8s117e NotReady <none> 6s v1.17.13
■10.ACI CNI Pluginの構成(Kubectl)
acc-provisionでACI環境の構成と同時に生成したACI CNI構成用のYAMLファイルを利用して、ACI CNIを展開します。
aci@k8s117a:~/k8s01$ kubectl apply -f aci-cni-config.yaml customresourcedefinition.apiextensions.k8s.io/acicontainersoperators.aci.ctrl created namespace/aci-containers-system created customresourcedefinition.apiextensions.k8s.io/snatglobalinfos.aci.snat created customresourcedefinition.apiextensions.k8s.io/snatlocalinfos.aci.snat created customresourcedefinition.apiextensions.k8s.io/snatpolicies.aci.snat created customresourcedefinition.apiextensions.k8s.io/nodeinfos.aci.snat created customresourcedefinition.apiextensions.k8s.io/rdconfigs.aci.snat created customresourcedefinition.apiextensions.k8s.io/aciistiooperators.aci.istio created configmap/aci-operator-config created configmap/aci-containers-config created configmap/snat-operator-config created secret/aci-user-cert created serviceaccount/aci-containers-controller created serviceaccount/aci-containers-host-agent created clusterrole.rbac.authorization.k8s.io/aci-containers:controller created clusterrole.rbac.authorization.k8s.io/aci-containers:host-agent created clusterrolebinding.rbac.authorization.k8s.io/aci-containers:controller created clusterrolebinding.rbac.authorization.k8s.io/aci-containers:host-agent created daemonset.apps/aci-containers-host created daemonset.apps/aci-containers-openvswitch created deployment.apps/aci-containers-controller created serviceaccount/aci-containers-operator created clusterrole.rbac.authorization.k8s.io/aci-containers-operator created clusterrolebinding.rbac.authorization.k8s.io/aci-containers-operator created deployment.apps/aci-containers-operator created aci@k8s117a:~/k8s01$
ACI CNIに関連するコンテナは、Namespace "aci-containers-system" に展開されます。オンライン経由で取得する場合には、ダウンロードと展開にある程度時間がかかります。Namespace "aci-containers-system" 内の全PodのステータスがRunningになるまでしばらくお待ち下さい。
★初期ステータス
aci@k8s117a:~/k8s01$ kubectl get pods -n aci-containers-system -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES aci-containers-controller-5c67d647c6-sfz2c 0/1 ContainerCreating 0 41s 10.101.0.149 k8s117e <none> <none> aci-containers-host-57lt2 0/3 ContainerCreating 0 42s 10.101.0.146 k8s117b <none> <none> aci-containers-host-5hnl4 0/3 ContainerCreating 0 42s 10.101.0.147 k8s117c <none> <none> aci-containers-host-89jg9 0/3 ContainerCreating 0 42s 10.101.0.149 k8s117e <none> <none> aci-containers-host-cbtvb 0/3 ContainerCreating 0 42s 10.101.0.148 k8s117d <none> <none> aci-containers-host-snlbs 0/3 ContainerCreating 0 42s 10.101.0.145 k8s117a <none> <none> aci-containers-openvswitch-9kc7z 0/1 ContainerCreating 0 42s 10.101.0.146 k8s117b <none> <none> aci-containers-openvswitch-chhkk 0/1 ContainerCreating 0 42s 10.101.0.145 k8s117a <none> <none> aci-containers-openvswitch-dzh8n 0/1 ContainerCreating 0 41s 10.101.0.148 k8s117d <none> <none> aci-containers-openvswitch-l8m2b 0/1 ContainerCreating 0 41s 10.101.0.149 k8s117e <none> <none> aci-containers-openvswitch-v6tjh 0/1 ContainerCreating 0 42s 10.101.0.147 k8s117c <none> <none> aci-containers-operator-6b7c66dcf7-dndbl 0/1 ContainerCreating 0 40s 10.101.0.147 k8s117c <none> <none> aci@k8s117a:~/k8s01$
★最終的な状態
aci@k8s117a:~/k8s01$ kubectl get pods -n aci-containers-system -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES aci-containers-controller-5c67d647c6-sfz2c 1/1 Running 0 20m 10.101.0.149 k8s117e <none> <none> aci-containers-host-57lt2 3/3 Running 0 20m 10.101.0.146 k8s117b <none> <none> aci-containers-host-5hnl4 3/3 Running 0 20m 10.101.0.147 k8s117c <none> <none> aci-containers-host-89jg9 3/3 Running 0 20m 10.101.0.149 k8s117e <none> <none> aci-containers-host-cbtvb 3/3 Running 0 20m 10.101.0.148 k8s117d <none> <none> aci-containers-host-snlbs 3/3 Running 0 20m 10.101.0.145 k8s117a <none> <none> aci-containers-openvswitch-9kc7z 1/1 Running 0 20m 10.101.0.146 k8s117b <none> <none> aci-containers-openvswitch-chhkk 1/1 Running 0 20m 10.101.0.145 k8s117a <none> <none> aci-containers-openvswitch-dzh8n 1/1 Running 0 20m 10.101.0.148 k8s117d <none> <none> aci-containers-openvswitch-l8m2b 1/1 Running 0 20m 10.101.0.149 k8s117e <none> <none> aci-containers-openvswitch-v6tjh 1/1 Running 0 20m 10.101.0.147 k8s117c <none> <none> aci-containers-operator-6b7c66dcf7-dndbl 1/1 Running 0 20m 10.101.0.147 k8s117c <none> <none> aci@k8s117a:~/k8s01$
■11.ACIからの状態確認
ACI CNIが展開・実行されたことで、ACI側からもKubernetes環境の情報やステータスを確認・連携することが可能となります。以下の項目についてAPICからの認識ステータスを確認して下さい。
■12.Kubernetes環境へのテストアプリの展開と確認
ここでは、kubernetesのチュートリアルで用意されているguestbookアプリケーションを利用して確認を実施します。guestbookは、デフォルトでは3つのフロントエンドPodと、1つのRedis Master DB Pod、2つのRedis Slave DB Podが展開されるコンテナアプリケーションです。
guestbookアプリケーションの詳細については、以下のURLを参照して下さい。
https://kubernetes.io/docs/tutorials/stateless-application/guestbook/
guestbook-all-in-one.yaml ファイルを適当なフォルダに配置します。
namespace "guestbook" を作成します。
kubectl create namespace guestbook
namespace "guestbook" にコンテナアプリケーションguestbookを展開します。
aci@k8s117a:~/k8s01/guestbook$ kubectl apply -n guestbook -f guestbook-all-in-one.yaml service/redis-master created deployment.apps/redis-master created service/redis-slave created deployment.apps/redis-slave created service/frontend created deployment.apps/frontend created aci@k8s117a:~/k8s01/guestbook$
必要なコンテナイメージがダウンロードされ展開されるまで待ちます。
aci@k8s117a:~/k8s01/guestbook$ kubectl get pods -n guestbook -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES frontend-6cb7f8bd65-52st8 1/1 Running 0 9m53s 10.102.0.74 k8s117c <none> <none> frontend-6cb7f8bd65-8rkvk 1/1 Running 0 9m53s 10.102.0.132 k8s117e <none> <none> frontend-6cb7f8bd65-zxctb 1/1 Running 0 9m53s 10.102.0.101 k8s117d <none> <none> redis-master-7db7f6579f-ttcs2 1/1 Running 0 9m53s 10.102.0.131 k8s117e <none> <none> redis-slave-5bdcfd74c7-9px96 1/1 Running 0 9m53s 10.102.0.100 k8s117d <none> <none> redis-slave-5bdcfd74c7-vc8mt 1/1 Running 0 9m53s 10.102.0.73 k8s117c <none> <none> aci@k8s117a:~/k8s01/guestbook$ kubectl get svc -n guestbook NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE frontend NodePort 10.106.217.245 <none> 80:31729/TCP 10m redis-master ClusterIP 10.106.23.201 <none> 6379/TCP 10m redis-slave ClusterIP 10.106.148.197 <none> 6379/TCP 10m aci@k8s117a:~/k8s01/guestbook$
L3outを経由して外部から内部への接続が可能となっている場合は、外部ネットワークからfrontendのCluster IPに接続しWeb UIが表示されることを確認して下さい。
また、APIC Web UI から、以下を確認して下さい。
■13.NamespaceとEPGのマッピング動作確認
ACI CNIを利用すると、ClusterやNamespace、Deploymentなどの単位でEPGへのマッピングを動的に制御することが可能です。これにより、ACIのEPGとContractの仕組みを使ってNamespace間の通信ルールを制御することが可能となります。
デフォルトでPodが紐付けられる "aci-containers-default" EPGから別のEPGに紐付けを変更したい場合には、事前に手動でEPGの作成と適切なContractの適用が必要となります。
EPGへのマッピングにはKubernetesが持つAnnotationの仕組みを利用するためkubectlコマンドで構成することも可能ですが、acc-provisionのインストールによって利用可能となっているacikubectlコマンドを利用すると、より直感的かつシンプルなコマンドで構成を行うことが可能です。
以下では、EPG "guestbook" に、Namespace "guestbook" を紐付ける例を示します。
acikubectl コマンドを利用する場合
aci@k8s117a:~/k8s01/guestbook$ acikubectl set default-eg namespace guestbook -t tsetaka_k8s -a aci-containers-tsetaka_lab_k8s -g guestbook Setting default endpoint group: Endpoint Group: Tenant: tsetaka_k8s App profile: aci-containers-tsetaka_lab_k8s Endpoint group: guestbook
kubectl コマンドを利用する場合
kubectl annotate namespace guestbook 'opflex.cisco.com/endpoint-group={"tenant":"tsetaka_k8s","app-profile":"aci-containers-tsetaka_lab_k8s","name":"guestbook"}'
以下のようにNamespaceに対してAnnotationが構成されます
aci@k8s117a:~/k8s01/guestbook$ kubectl describe namespace guestbook Name: guestbook Labels: <none> Annotations: opflex.cisco.com/endpoint-group: {"tenant":"tsetaka_k8s","app-profile":"aci-containers-tsetaka_lab_k8s","name":"guestbook"} Status: Active No resource quota. No LimitRange resource. aci@k8s117a:~/k8s01/guestbook$
この操作により、Namespace "guestbook" に紐づく全Podが、自動的に EPG "aci-containers-default" から、指定したEPG (本例では "guestbook")に移動します。
この様に、EPGとContractの仕組みを用いたコンテナに対するセキュリティは、Kubernetes側で構成するNetwork Policyと組み合わせて利用頂くことができます。個別アプリケーション毎の詳細なセキュリティの構成はNetwork Policyを利用して実装する場合であっても、共通のルールや、最低限のセキュリティ基準をContractを用いて強制することで、セキュリティ構成のモレやヌケを防止することが可能です。
■14.基本的なPing疎通テスト
コンテナ以外との疎通を確認したい場合には、物理サーバやVMを適切なEPGに紐づけて確認いただけますが、シンプルにNamespaceなどにコンテナを展開してPing疎通などを確認したい場合には、適当なコンテナをKubernetes環境に展開して確認頂くことも可能です。
kubectl run ssh-client --image=kroniak/ssh-client --restart=Never --rm -it /bin/sh
ShellからPingなどの疎通をテスト頂けます。
aci@k8s117a:~$ kubectl run ssh-client --image=kroniak/ssh-client --restart=Never --rm -it /bin/sh If you don't see a command prompt, try pressing enter. / # / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000 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 3: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 8900 qdisc noqueue state UP link/ether 5e:94:69:32:f0:7e brd ff:ff:ff:ff:ff:ff inet 10.102.0.135/16 brd 10.102.255.255 scope global eth0 valid_lft forever preferred_lft forever / #
■15.テストアプリの外部アクセス提供(External IP)
guestbookコンテナアプリケーションはDeploymentとしては frontend, redis-master, redis-slave の3つから構成されており、frontendのPod数を増減させることによってフロントエンドをスケールアウトさせることが可能です。
以下の場合、フロントエンドは3つのPodで構成されており、各PodはKubernetesによって自動的に各Nodeに分散されて配置されます。
aci@k8s117a:~/k8s01/guestbook$ kubectl get deployment -n guestbook NAME READY UP-TO-DATE AVAILABLE AGE frontend 3/3 3 3 59m redis-master 1/1 1 1 59m redis-slave 2/2 2 2 59m
Deployment "frontend" を構成しているPodの配置状態を確認することも可能です。以下のように、3台のWorker Nodeに分散して配置されていることがわかります。
aci@k8s117a:~/k8s01/guestbook$ kubectl get pods -n guestbook -o wide | grep frontend frontend-6cb7f8bd65-52st8 1/1 Running 0 61m 10.102.0.74 k8s117c <none> <none> frontend-6cb7f8bd65-8rkvk 1/1 Running 0 61m 10.102.0.132 k8s117e <none> <none> frontend-6cb7f8bd65-zxctb 1/1 Running 0 61m 10.102.0.101 k8s117d <none> <none> aci@k8s117a:~/k8s01/guestbook$
ACIはL3outを通じて外部に対してコンテナに対する接続を構成するExternal IPを設定することが可能です。先程のguestbookコンテナアプリケーションに対して外部からの接続を構成するためには、frontendのtypeをNodePortからLoadBalancerに変更します。
kubectl -n guestbook edit svc frontend
→ "type: NodePort" を "type: LoadBalancer" に変更して保存する
External IPとして、external_dynamicに設定したSubnet範囲からIPアドレスが払い出されたことを確認します
aci@k8s117a:~/k8s01/guestbook$ kubectl -n guestbook get svc frontend NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE frontend LoadBalancer 10.106.217.245 10.103.0.3 80:31729/TCP 51m
■16.External IPに対するACI PBR Service Graphの動作
このExternal IPアドレスへの接続をfrontend Podに振り分けるために、ACIはService Graph PBRの仕組みを活用しています。
上図のように、External IPを指定したExternal EPGと最初に用意した外部ネットワークを指定したExteranal EPGとの間にContractを構成しPBR Service Graphを構成することによって、ACIは外部からの通信をExteranal IPが指定されたExternal EPGに通信させる処理に対してPBRを適用し、サービスノードとして指定したWorker Nodeに対して通信を「折り曲げる」ことでExteranal IPに対する通信をWorker Node上に存在する実Podに転送します。
External IPに紐づくいずれかのPodが配置されたWorker Nodeに転送された通信は、Worker Node側のOVSによってNAT処理されて実際のPodに転送されます。Worker Nodeのからの戻りの通信はPBRによって折り曲げられた通信の戻りとなりますので、Contractの構成に基づいて外部に送信されます。これによって、ACIをロードバランサとして利用するExternal IP宛の通信が実現します。
guestbookのDeployment "frontend" は複数のPodで構成されている場合があり、それらのPodは複数のNodeに分散して配置されています。このDeploymentのレプリカ数は動的に変更が可能であり、自由な台数に増減させることができます。つまり、レプリカ数の増減に合わせて、動的にPodが動作するNodeに適切に通信を振り分ける必要があります。ACIはKubernetesとAPI連携することでExternal IPに紐づいたNodeをPBRによる振り分け先サービスノードとして動的に構成することができます。
以下は guestbookコンテナアプリケーションのDeployment "frontend" の構成レプリカ数を2に変更する例です。下記例の場合、frontend を構成するPodは Worker Node "k8s117c" と "k8s117d" で実行されている状態となっていることがわかります。
aci@k8s117a:~/k8s01/guestbook$ kubectl scale deployment frontend -n guestbook --replicas 2 deployment.apps/frontend scaled aci@k8s117a:~/k8s01/guestbook$ kubectl get pods -n guestbook -o wide | grep frontend frontend-6cb7f8bd65-52st8 1/1 Running 0 68m 10.102.0.74 k8s117c <none> <none> frontend-6cb7f8bd65-zxctb 1/1 Running 0 68m 10.102.0.101 k8s117d <none> <none> aci@k8s117a:~/k8s01/guestbook$
この状態の場合、External IP宛の通信がACI FabricにL3out経由で届いた際には、この2台のいずれかのノードに通信を振り分ける必要があります。ACIは、Service Graph PBR の仕組みを利用してこのロードバランス処理を提供することができます。ただし、このロードバランスはStatelessな処理となるため、StatefullなL4や高度なL7のロードバランスを必要とするような場合には専用LBを利用するなど別の仕組みを組み合わせて利用頂く必要があります。
ACIは、PBRで振り分け先サービスノードとして frontend Podが配置されたWorker Nodeの情報をKubernetesから取得し、動的に変更することでロードバランスの振り分け先を管理しています。上記のように、レプリカ数を2台とし、frontendを構成するPodが "k8s117c" および "k8s117d" となった状態では、下記のように正しくこれらのノードが振り分け先となっていることが確認できます([Tenant] - [Policies] - [Protocol] - [L4-L7 Policy-Based Redirect] - [(system_id)_(Namespace)_(Deployment)])。
ここで、レプリカ数を3に変更してみます。下記のように、新たにWorker Node "k8s117e" で frontend を構成する新しいPodが動作を始めたことが確認できます。
aci@k8s117a:~/k8s01/guestbook$ kubectl scale deployment frontend -n guestbook --replicas 3 deployment.apps/frontend scaled aci@k8s117a:~/k8s01/guestbook$ kubectl get pods -n guestbook -o wide | grep frontend frontend-6cb7f8bd65-52st8 1/1 Running 0 69m 10.102.0.74 k8s117c <none> <none> frontend-6cb7f8bd65-ghtd5 1/1 Running 0 3s 10.102.0.134 k8s117e <none> <none> frontend-6cb7f8bd65-zxctb 1/1 Running 0 69m 10.102.0.101 k8s117d <none> <none> aci@k8s117a:~/k8s01/guestbook$
上記捜査の結果、frontend を構成しているPodが動作するノードとして "k8s117e" が追加されたため、ACIは動的にPBRの宛先ノードとしてこの新規Worker Nodeを追加して登録します。これは自動的に行われるため、管理者が構成する必要はありません。
このPBR Service Graphにおいて、PBRサービスノードに対するIP SLAを構成することができるようになっており、acc-provisionツールで生成したACI構成用yamlファイルの中の以下のパラメータが利用されます。
service_monitor_interval: 5 # IPSLA interval probe time for PBR tracking
これにより、ICMPを利用して指定した秒数間隔で3回疎通が取れなければ振り分け先から外すIP SLAポリシーが設定されます。このように簡易的な生存監視も行うことが可能となっているため、複雑な処理やSSL終端を必要とするなどの要件がない場合にはACI Fabric自体をKubernetes環境に対する外部ロードバランサとして利用いただけます。
■17.Dynamic Routing利用時のExternal IP Subnetの広告に関して
対向のL3デバイス側でStatic Routeを利用している場合には不要ですが、Dynamic Routingを利用している場合には、ACIのL3outで extern_dynamic および extern_static で指定したPrefix範囲について対向のL3デバイスに経路情報をACIに向けるように経路情報を通知する必要があります。
これを構成するためには、L3outを構成しているBorder LeafにおいてStatic Routeを構成し、Next Hopを指定しない(Null)ことで対処することができます。合わせて、Route Mapの構成も必要です。詳細については、以下のURLを参照して下さい。
https://www.cisco.com/c/en/us/td/docs/switches/datacenter/aci/apic/sw/kb/b_Kubernetes_Integration_with_ACI.html#id_90191
■Appendix
ACI Kubernetes連携については、以下のTech Notesドキュメントを合わせて参考下さい。
F5連携を利用する場合は、以下のBlog記事や、F5 CISのドキュメントページなどを参考下さい。
https://blogs.cisco.com/datacenter/enable-consistent-application-services-for-containers
https://clouddocs.f5.com/containers/latest/
検索バーにキーワード、フレーズ、または質問を入力し、お探しのものを見つけましょう
シスコ コミュニティをいち早く使いこなしていただけるよう役立つリンクをまとめました。みなさんのジャーニーがより良いものとなるようお手伝いします