キャンセル
次の結果を表示 
次の代わりに検索 
もしかして: 
cancel
2492
閲覧回数
0
いいね!
0
コメント
takaochan
Cisco Employee
Cisco Employee

スクリーンショット 2020-11-06 12.26.25.png

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連携を構成される方は、以下動画を参考下さい。

 

  • ACI and Kubernetes Multi Cluster - Part 1/3 - Introduction
  • ACI and Kubernetes Multi Cluster - Part 2/3 - Kubernetes Cluster Bring Up

  • ACI and Kubernetes Multi Cluster - Part 3/3 - MSO KubeFed and ExternalDNS

本ページでは、基本的な手順としてKubernetesを構成しACI CNIを組み込む手順を説明しています。Kubernetesの構成方法はkubeadmを用いる方法以外にも多数ありますし、各社からより簡易な方法が提供されているソリューションもあります。それらを使用する場合には、適宜読み替えて判断してください。

 

ACIとKubernetesの連携は、Kubernetesがネットワークと連携するための標準化された仕組みであるCNIを用いて実装されているため、Kubernetesを利用するアプリケーションエンジニア側からはACIの存在を意識することなくKubernetesを利用頂くことが可能です。同時に、インフラリソースの管理者側からはKubernetes側のステータスを把握できるようになるとともに、必要に応じてACIのEPGおよびContractを用いたセキュリティルールの強制を行うなどのガバナンス管理を物理サーバや仮想マシンなどを利用する場合と同様に適用することができます。

スクリーンショット 2020-11-06 12.27.05.png

本ページでは、以下の準備と構成は完了していることを前提としています。

  • ACI Fabric
  • VMM Domain連携されたvSphere環境 (VMM連携して利用する場合)
  • Docker及びKubernetesをインストールするためのLinuxサーバ(物理サーバもしくは仮想マシン)
  • Internet経由でレポジトリにアクセスできる環境
  • 本ページでは、以下の環境で確認を行っています。
  • ACI 5.0, ACI 5.1 (UIのスクリーンショットは ACI 5.1ベースとなっています)
  • ACI CNI Plugin Release 5.0(2.20200831)
  • VMM Domain連携済みvSphere 6.7 Update 2
  • Ubuntu 18.04 (仮想マシン) x5台 … Control Plane Node x2, Worker Node x3
  • Docker 19.03.11
  • Kubernetes 1.17.13

ACIをKubernetesに連携するには、以下の手順での構成を行います。

  1. Kubernetesクラスタパラメータの決定
  2. 必要となるACI側の事前準備
  3. acc-provisionのインストールと構成ファイルの作成
  4. ACIの構成とCNIプラグイン構成ファイルの生成
  5. Linux環境の構成(ホスト名、Swapの無効化、ネットワークなど)
  6. Dockerのインストール
  7. Kubernetesのインストール
  8. Control Plane NodeのHA構成
  9. Kubernetesの構成(kubeadm)
  10. ACI CNI Pluginの構成(Kubectl)
  11. ACIからの状態確認
  12. Kubernetes環境へのテストアプリの展開と確認
  13. NamespaceとEPGのマッピング動作確認
  14. 基本的なPing疎通テスト
  15. テストアプリの外部アクセス提供(External IP)
  16. External IPに対するACI PBR Service Graphの動作
  17. Dynamic Routing利用時のExternal IP Subnetの広告に関して

■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側の事前準備

スクリーンショット 2020-11-06 12.26.51.png

ACI CNIを用いたKubernetes連携を構成する前に、ACI側では以下の構成を事前に済ませておく必要があります。また、これらの項目は、後ほど作成するACI構成用のyamlファイルの中で正しく同じ名前を指定する必要があります。

  • Access Policyまわりの構成 (AEP, Interface Policy Group, Interface Profile, Switch Profileなど)
  • Tenantの作成 ※commonテナント利用の場合は不要
  • VRFの作成
  • L3outの作成(合わせてExternal EPGの作成) ※VRFに紐付けること

■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側に以下が指定パラメータに合わせて自動的に構成されます。

  • Physical Domain
  • VLAN Pool
  • AEP ※定義ファイルで指定したAEPが存在しない場合のみ
  • Kubernetes用VMM Domain ※この時点では、まだサーバ側の準備が整っていないため、枠組みだけが作成されます
  • Bridge Domain (BD)
  • Application Profile
  • EPG
  • Contract
  • Filter

 2020-10-26 19.44.18.png

必要に応じて、Kubernetesノードの接続に利用しているInterface Policy Groupに対してAEPを適切に紐付けるなど、追加で手動での構成が必要となる場合があります。

 

■05.Linux環境の構成(ホスト名、Swapの無効化、ネットワークなど)

Kubernetes用Linuxでは、以下の要件を満たす必要があります。

  • Default GWは、ACI Leaf側に接続したNICに向いている必要がある (複数NIC構成も可能ですが、Default GWはACI Leaf接続側NICに向けられている必要があります)
  • /etc/hostname ファイルに一意のホスト名が定義されている
  • /etc/hosts ファイルでホスト名がローカルのループバックに紐付けられている(127.0.0.1 もしくは 127.0.1.1 などの 127.0.0.0/8 範囲のIPアドレス)

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 Leaf接続側インターフェイスにDefault GWが向いていること、Multicastアドレスについて、Infra VLANに経路が向いていること
  • ACI Leaf接続側インターフェイスのMTUサイズが指定したとおりになっていること
  • kubeapi_vlan インターフェイスに設定した静的IPが意図したとおりになっており、ACI側BDに構成したGWアドレスおよび他のKubernetesノードとの間でPing疎通すること (以下例では 10.101.0.145)
  • infra_vlan インターフェイスでAPICからDHCPによるIPアドレスの払い出しが正常に適用されていること及び全APICと問題なくPing疎通すること (以下例では 10.1.24.65/16、本構成では、ACI側のInfra VLANを10.1.0.0/16としているため、10.1.0.0/16の範囲から払い出されているが、デフォルト定義を利用した場合は10.0.0.0/16範囲の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からの認識ステータスを確認して下さい。

 

  • [Virtual Networking] - [Containers] - [Kubernetes] (ACI 5.1以降では、[Virtual Networking] - [Kubernetes])
    • Nodes配下で、Kubernetesクラスタを構成している全ノードが表示され、Statusが "Connected" となっていること
       2020-11-06 10.38.44.png
    • Namespaces で Kubernetesに構成済の全Namespaceが参照できること
       2020-11-06 10.39.55.png
    • Namespace "kube-system" において、coredns Podが認識されていること
       2020-10-26 17.15.14.png
  • Kubernetes用のVRFを展開したTenantの[Application Profiles] - [aci-containers-<system id>]
    • [aci-containers-nodes] EPGにおいて、全Kubernetesノードが認識されていること(Encapはkubeapi_vlanで指定したVLAN)
       2020-10-26 17.17.25.png
    • [aci-containers-system] EPGにおいて、corednsが認識されていること(EncapはVXLAN)
       2020-10-26 17.17.00.png


■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 から、以下を確認して下さい。

  • [Virtual Networking] - [Containers] - [Kubernetes] (ACI 5.1以降では、[Virtual Networking] - [Kubernetes])
    • Namespaces で Kubernetesに構成した Namespace "guestbook"が参照できること
    • Namespace "guestbook" において、展開されている全Podが認識されていること 2020-11-06 10.41.07.png
      ※上記例ではIPアドレスを持っていないPodがありますが、DeploymentのReplica数を変更したりEPGへの紐付けを変更(やり方は後述)したりしたため、一時的に情報が残ってしまっているためです
  • Kubernetes用のVRFを展開したTenantの[Application Profiles] - [aci-containers-<system id>]
    • EPG "aci-containers-default" において、展開されているNamespace "guestbook"に紐づく全Podが認識されていること
       2020-11-06 10.47.16.png

 

■13.NamespaceとEPGのマッピング動作確認

ACI CNIを利用すると、ClusterやNamespace、Deploymentなどの単位でEPGへのマッピングを動的に制御することが可能です。これにより、ACIのEPGとContractの仕組みを使ってNamespace間の通信ルールを制御することが可能となります。

スクリーンショット 2020-11-06 12.28.48.png

デフォルトでPodが紐付けられる "aci-containers-default" EPGから別のEPGに紐付けを変更したい場合には、事前に手動でEPGの作成と適切なContractの適用が必要となります。

  • EPGを適切な名前で作成します
  • BDは "aci-containers-<system_id>" を紐付けます
  • VMM Domain として Kubernetes 連携に利用しているDomainを紐付けます
  • 適切なContractを構成し適用(Provide/Consume)します

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")に移動します。

 2020-11-06 11.25.17.png

この様に、EPGとContractの仕組みを用いたコンテナに対するセキュリティは、Kubernetes側で構成するNetwork Policyと組み合わせて利用頂くことができます。個別アプリケーション毎の詳細なセキュリティの構成はNetwork Policyを利用して実装する場合であっても、共通のルールや、最低限のセキュリティ基準をContractを用いて強制することで、セキュリティ構成のモレやヌケを防止することが可能です。

スクリーンショット 2020-11-06 12.29.06.png

 

■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の仕組みを活用しています。

スクリーンショット 2020-11-06 12.29.25.png

上図のように、External IPを指定したExternal EPGと最初に用意した外部ネットワークを指定したExteranal EPGとの間にContractを構成しPBR Service Graphを構成することによって、ACIは外部からの通信をExteranal IPが指定されたExternal EPGに通信させる処理に対してPBRを適用し、サービスノードとして指定したWorker Nodeに対して通信を「折り曲げる」ことでExteranal IPに対する通信をWorker Node上に存在する実Podに転送します。

 2020-11-04 17.59.47.png

External IPに紐づくいずれかのPodが配置されたWorker Nodeに転送された通信は、Worker Node側のOVSによってNAT処理されて実際のPodに転送されます。Worker Nodeのからの戻りの通信はPBRによって折り曲げられた通信の戻りとなりますので、Contractの構成に基づいて外部に送信されます。これによって、ACIをロードバランサとして利用するExternal IP宛の通信が実現します。

スクリーンショット 2020-11-06 12.30.26.png

 2020-11-04 17.57.56.png

 

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を利用するなど別の仕組みを組み合わせて利用頂く必要があります。

スクリーンショット 2020-11-06 12.30.41.png

ACIは、PBRで振り分け先サービスノードとして frontend Podが配置されたWorker Nodeの情報をKubernetesから取得し、動的に変更することでロードバランスの振り分け先を管理しています。上記のように、レプリカ数を2台とし、frontendを構成するPodが "k8s117c" および "k8s117d" となった状態では、下記のように正しくこれらのノードが振り分け先となっていることが確認できます([Tenant] - [Policies] - [Protocol] - [L4-L7 Policy-Based Redirect] - [(system_id)_(Namespace)_(Deployment)])。

 2020-11-04 17.54.57.png

ここで、レプリカ数を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を追加して登録します。これは自動的に行われるため、管理者が構成する必要はありません。

 2020-11-04 17.53.12.png

このPBR Service Graphにおいて、PBRサービスノードに対するIP SLAを構成することができるようになっており、acc-provisionツールで生成したACI構成用yamlファイルの中の以下のパラメータが利用されます。

service_monitor_interval: 5 # IPSLA interval probe time for PBR tracking

 2020-11-04 17.52.39.png

これにより、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ドキュメントを合わせて参考下さい。

https://www.cisco.com/c/en/us/td/docs/switches/datacenter/aci/apic/sw/kb/b_Kubernetes_Integration_with_ACI.html

F5連携を利用する場合は、以下のBlog記事や、F5 CISのドキュメントページなどを参考下さい。

https://blogs.cisco.com/datacenter/enable-consistent-application-services-for-containers

https://clouddocs.f5.com/containers/latest/

 

 

 

 

 

Getting Started

検索バーにキーワード、フレーズ、または質問を入力し、お探しのものを見つけましょう

シスコ コミュニティをいち早く使いこなしていただけるよう役立つリンクをまとめました。みなさんのジャーニーがより良いものとなるようお手伝いします