TerraformでOracle Cloudにk8sクラスタをデプロイする
今更ながら、OCI(Oracle Cloud Infrastructure)のAlway Freeプランが改訂された事を知りました。
以前と比べると、VM.Standard.A1.Flexが4 OCPU/24 GBを追加で使えるようになっているようです。
既にAlways Freeのものを以下のリポジトリで管理していたので、VM.Standard.A1.Flexで4 OCPU/24 GB分のInstanceを新たに作成します。
作成した(している)コードは以下においてあります。
Ubuntu20.04やCentos8のARM shapeは未対応?で使用できないようでした。
なので、初めてOracle Linuxを使ってみます。
試しに既にデプロイしているVM.Standard.E2.1.Microのコードをもとに、shapeやimage source_idだけを変更して1台だけデプロイすると、早速エラーになりました。
Terraform v1.0.0
on linux_amd64
Initializing plugins and modules...
oci_core_instance.oracle01[0]: Creating...
╷
│ Error: 400-InvalidParameter
│ Provider version: 4.36.0, released on 2021-07-21.
│ Service: Core Instance
│ Error Message: Invalid ShapeConfig: null (Cannot launch flexible instance without ShapeConfig)
│ OPC request ID: 9c2a2cb5d6b9cf61fceaae254bb6eb95/05805FBC9837D61713DEA7755EC7976E/A505946AF66C8436E8F88CB815AAA916
│ Suggestion: Please update the parameter(s) in the Terraform config as per error message Invalid ShapeConfig: null (Cannot launch flexible instance without ShapeConfig)
│
│
│ with oci_core_instance.oracle01[0],
│ on compute.tf line 44, in resource "oci_core_instance" "oracle01":
│ 44: resource "oci_core_instance" "oracle01" {
│
╵
Error Message: Invalid ShapeConfig: null (Cannot launch flexible instance without ShapeConfig)
Flexible instanceなので、shape_configが空であると怒られてしまいます。
以下を追加してリトライしました。
shape_config {
ocpus = 1
memory_in_gbs = 6
}
次はデプロイがうまくいきました。一番上が今回作ったものになります。
1台目のデプロイはうまくいったので、4台分デプロイしてみます。
$ git diff
diff --git a/terraform/compute.tf b/terraform/compute.tf
index 3688d2f..f97cc41 100644
--- a/terraform/compute.tf
+++ b/terraform/compute.tf
@@ -20,7 +20,7 @@ resource "oci_core_instance" "ubuntu" {
}
resource "oci_core_instance" "oracle_linux" {
- count = 1
+ count = 4
availability_domain = oci_core_subnet.subnet01.availability_domain
compartment_id = var.COMPARTMENT_OCID
shape = "VM.Standard.A1.Flex"
変更点は上記だけなので、mainブランチに直接pushしてしまいます。
Terraform v1.0.0
on linux_amd64
Initializing plugins and modules...
oci_core_instance.oracle_linux[3]: Creating...
oci_core_instance.oracle_linux[2]: Creating...
oci_core_instance.oracle_linux[1]: Creating...
╷
│ Error: 500-InternalError
│ Provider version: 4.36.0, released on 2021-07-21.
│ Service: Core Instance
│ Error Message: Out of host capacity.
│ OPC request ID: ec9f41ac843ad40d151603a4381a550d/78E8B02D020448FEBF521B56923CBD24/774E6C2486F80B0DBBBC0251A5922882
│ Suggestion: The service for this resource encountered an error. Please contact support for help with service: Core Instance
│
│
│ with oci_core_instance.oracle_linux[1],
│ on compute.tf line 22, in resource "oci_core_instance" "oracle_linux":
│ 22: resource "oci_core_instance" "oracle_linux" {
Error Message: Out of host capacity.
と言うメッセージが返ってきて、エラーになってしまいました。
こ、これは以前にもありましたが、単純にOCI側にリソースがなくてinstanceが作れていない状態です。
試しにGUIで作ると以下のような警告が出てきて作成する事ができません。
こればかりはOracle様がリソース追加してくれる事を、気長に待つしかないです
terraform apply
terraform destroy
を繰り返していたら、1台も作れなくなってしまいました。。。。。
どうやら大人気でリソースが少ないので、期間を置いて試してみます。
fishを使っているので、こんな感じで作成されるまで繰り返します。。。
set $status 1 # 何でもいいのでエラーコード1にする
while [ $status = 1 ]; terraform apply -auto-approve ;end
instance作成のtfファイルは出来たので、次はk8s周りの設定をしていきます。
現状の構成から以下の変更を加えようと思います。
- NAT Gatewayは使っていない
- PublicIPを持ったVM.Standard.E2.1.Microが2台ある
- NAT,Bastion用途で使用する
- Public SubnetとPrivateSubnetに分ける
- PublicIPを持ったLBが1台ある
- k8sクラスタにバランシングする
To Do
terraformでやること
-
Instance
-
bastion
-
SSH agent forwardingの許可-> 不要でした - NAT
- (Optional)iptablesの設計を決める -> とりあえず最低限のNAT設定のみ
-
(Optional)
keepalived-> 使うならマネージドiLB
-
-
k8s
- cloud-initでDockerをインストール
-
bastion
-
Network
- Private / Public Subnetの分離
- eLBのバックエンドセットをk8sクラスタに更新
- (Optional)iLBのバックエンドセットをbastionに更新し、Public SegmentのGWにする
- RKEのterraform
Reference
既にssh-agent-forwardingでログインできました。
恥ずかしながら、ログインユーザが間違ってました。
Oracle Linuxの場合は、デフォルトでopc
でした。
ubuntu@ubuntu01:~$ ssh opc@oracle01.vcn01
The authenticity of host 'oracle01.vcn01 (192.168.0.4)' can't be established.
ECDSA key fingerprint is SHA256:yCZFVuomQ4Oh6UrbXi6fhA98K1HYF3hA+Lxl51O2YqQ.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'oracle01.vcn01' (ECDSA) to the list of known hosts.
Last login: Mon Jul 26 03:15:53 2021 from ubuntu02.vcn01.vcn01.oraclevcn.com
[opc@oracle01 ~]$ cat /etc/os-release
NAME="Oracle Linux Server"
VERSION="7.9"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="7.9"
PRETTY_NAME="Oracle Linux Server 7.9"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:7:9:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://bugzilla.oracle.com/"
ORACLE_BUGZILLA_PRODUCT="Oracle Linux 7"
ORACLE_BUGZILLA_PRODUCT_VERSION=7.9
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=7.9
Subnetの分離
現在使用しているvcnには、PublicIPを持たないホストがいるため、以下のようにsubnetを分離してNATを利用し、PrivateIPしか持たないホストでも外部に通信ができるようにします。
- vcn01: 192.168.0.0/16
- Public Subnet: 192.168.0.0/24
- Bastion用のインスタンスが2台存在
- Ubuntu20.04
- PublicIPを持っている
- 外部からSSHができる
- NAT設定する
- Bastion用のインスタンスが2台存在
- Private Subnet: 192.168.1.0/24
- k8sクラスタ用のインスタンスが1~4台存在
- Oracle Linux 7.9
- PrivateIPのみ持っている
- デフォルトルートをPublic SubnetにあるNATのインスタンスに向ける
- k8sクラスタ用のインスタンスが1~4台存在
- Public Subnet: 192.168.0.0/24
BastionサーバにNAT設定
PublicIPを持ったVM.Standard.E2.1.Micro(これ以降bastionと呼びます)にNATの設定を実施します。
cloud-initを使って起動時にコマンドを実行する設定をしました。
以下のようにPrivate Subnetをnatする事で、外部に疎通ができるようになりました。
- ens3はinstanceのInterface
- 192.168.1.0/24はPrivate Subnetのsegment
#cloud-config
# vim:syntax=yaml
runcmd:
- sudo sysctl -w net.ipv4.ip_forward=1
- sudo sed -i -e "s/^#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g" /etc/sysctl.conf
- sudo iptables -F
- sudo iptables -I FORWARD 1 -i ens3 -o ens3 -j ACCEPT
- sudo iptables -t nat -A POSTROUTING -o ens3 -s 192.168.1.0/24 -j MASQUERADE
Oracle LinuxにDockerをインストール
スタンドアロンで出来る方法に絞って、Dockerをインストールしていきます。(そのほかに知っている方がいれば教えて頂きたいです。)
Rancherのスクリプトを使う
まずは、一番手軽な方法から試してみます。
以下のスクリプトを実行するだけになります。
curl https://releases.rancher.com/install-docker/20.10.sh | sh
実行しましたが、エラーとなってしまいました。
+ sh -c 'yum install -y -q docker-ce-cli-20.10.7-3.el7'
警告: /var/cache/yum/aarch64/7Server/docker-ce-stable/packages/docker-ce-cli-20.10.7-3.el7.aarch64.rpm: ヘッダー V4 RSA/SHA512 Signature、鍵 ID 621e9f35: NOKEY
docker-ce-cli-20.10.7-3.el7.aarch64.rpm の公開鍵がインストールされていません
Importing GPG key 0x621E9F35:
Userid : "Docker Release (CE rpm) <docker@docker.com>"
Fingerprint: 060a 61c5 1b55 8a7f 742b 77aa c52f eb6b 621e 9f35
From : https://download.docker.com/linux/centos/gpg
+ sh -c 'yum install -y -q docker-ce-20.10.7-3.el7'
エラー: パッケージ: docker-ce-rootless-extras-20.10.7-3.el7.aarch64 (docker-ce-stable)
要求: fuse-overlayfs >= 0.7
エラー: パッケージ: docker-ce-rootless-extras-20.10.7-3.el7.aarch64 (docker-ce-stable)
要求: slirp4netns >= 0.4
問題を回避するために --skip-broken を用いることができます。
これらを試行できます: rpm -Va --nofiles --nodigest
aarch64
と言うメッセージがあるように、arm64には対応していない?みたいです。
$ systemctl status docker
Unit docker.service could not be found.
そんな時に、Oracle本家のブログ記事を見つけました。
yum install docker-engine
だけすればdockerをインストールできるとのことです。
実行ログ
[opc@oracle01 ~]$ sudo yum install -y docker-engine
読み込んだプラグイン:langpacks, ulninfo
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ docker-engine.aarch64 0:19.03.11.ol-13.el7 を インストール
--> 依存性の処理をしています: runc >= 3:1.0.0-1.rc95 のパッケージ: docker-engine-19.03.11.ol-13.el7.aarch64
--> 依存性の処理をしています: containerd >= 1.4.8 のパッケージ: docker-engine-19.03.11.ol-13.el7.aarch64
--> 依存性の処理をしています: container-selinux >= 2:2.77 のパッケージ: docker-engine-19.03.11.ol-13.el7.aarch64
--> 依存性の処理をしています: docker-cli のパッケージ: docker-engine-19.03.11.ol-13.el7.aarch64
--> トランザクションの確認を実行しています。
---> パッケージ container-selinux.noarch 2:2.119.2-1.911c772.el7_8 を インストール
---> パッケージ containerd.aarch64 0:1.4.8-1.el7 を インストール
---> パッケージ docker-cli.aarch64 0:19.03.11.ol-13.el7 を インストール
---> パッケージ runc.aarch64 3:1.0.0-1.rc95.el7 を インストール
--> 依存性の処理をしています: criu のパッケージ: 3:runc-1.0.0-1.rc95.el7.aarch64
--> トランザクションの確認を実行しています。
---> パッケージ criu.aarch64 0:3.12-2.el7 を インストール
--> 依存性の処理をしています: libprotobuf-c.so.1(LIBPROTOBUF_C_1.0.0)(64bit) のパッケージ: criu-3.12-2.el7.aarch64
--> 依存性の処理をしています: libprotobuf-c.so.1()(64bit) のパッケージ: criu-3.12-2.el7.aarch64
--> 依存性の処理をしています: libnet.so.1()(64bit) のパッケージ: criu-3.12-2.el7.aarch64
--> トランザクションの確認を実行しています。
---> パッケージ libnet.aarch64 0:1.1.6-7.el7 を インストール
---> パッケージ protobuf-c.aarch64 0:1.0.2-3.el7 を インストール
--> 依存性解決を終了しました。
依存性を解決しました
=============================================================================================================================================
Package アーキテクチャー バージョン リポジトリー 容量
=============================================================================================================================================
インストール中:
docker-engine aarch64 19.03.11.ol-13.el7 ol7_oci_included 14 M
依存性関連でのインストールをします:
container-selinux noarch 2:2.119.2-1.911c772.el7_8 ol7_oci_included 39 k
containerd aarch64 1.4.8-1.el7 ol7_oci_included 22 M
criu aarch64 3.12-2.el7 ol7_latest 430 k
docker-cli aarch64 19.03.11.ol-13.el7 ol7_oci_included 21 M
libnet aarch64 1.1.6-7.el7 ol7_latest 56 k
protobuf-c aarch64 1.0.2-3.el7 ol7_latest 27 k
runc aarch64 3:1.0.0-1.rc95.el7 ol7_oci_included 2.7 M
トランザクションの要約
=============================================================================================================================================
インストール 1 パッケージ (+7 個の依存関係のパッケージ)
総ダウンロード容量: 60 M
インストール容量: 276 M
Downloading packages:
(1/8): container-selinux-2.119.2-1.911c772.el7_8.noarch.rpm | 39 kB 00:00:00
(2/8): criu-3.12-2.el7.aarch64.rpm | 430 kB 00:00:00
(3/8): containerd-1.4.8-1.el7.aarch64.rpm | 22 MB 00:00:02
(4/8): docker-cli-19.03.11.ol-13.el7.aarch64.rpm | 21 MB 00:00:02
(5/8): libnet-1.1.6-7.el7.aarch64.rpm | 56 kB 00:00:00
(6/8): protobuf-c-1.0.2-3.el7.aarch64.rpm | 27 kB 00:00:00
(7/8): runc-1.0.0-1.rc95.el7.aarch64.rpm | 2.7 MB 00:00:00
(8/8): docker-engine-19.03.11.ol-13.el7.aarch64.rpm | 14 MB 00:00:01
---------------------------------------------------------------------------------------------------------------------------------------------
合計 15 MB/s | 60 MB 00:00:03
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
インストール中 : 2:container-selinux-2.119.2-1.911c772.el7_8.noarch 1/8
インストール中 : containerd-1.4.8-1.el7.aarch64 2/8
インストール中 : protobuf-c-1.0.2-3.el7.aarch64 3/8
インストール中 : libnet-1.1.6-7.el7.aarch64 4/8
インストール中 : criu-3.12-2.el7.aarch64 5/8
インストール中 : 3:runc-1.0.0-1.rc95.el7.aarch64 6/8
インストール中 : docker-cli-19.03.11.ol-13.el7.aarch64 7/8
インストール中 : docker-engine-19.03.11.ol-13.el7.aarch64 8/8
xfs_info: cannot open /var/lib: ディレクトリです
検証中 : containerd-1.4.8-1.el7.aarch64 1/8
検証中 : docker-cli-19.03.11.ol-13.el7.aarch64 2/8
検証中 : docker-engine-19.03.11.ol-13.el7.aarch64 3/8
検証中 : 2:container-selinux-2.119.2-1.911c772.el7_8.noarch 4/8
検証中 : criu-3.12-2.el7.aarch64 5/8
検証中 : 3:runc-1.0.0-1.rc95.el7.aarch64 6/8
検証中 : libnet-1.1.6-7.el7.aarch64 7/8
検証中 : protobuf-c-1.0.2-3.el7.aarch64 8/8
インストール:
docker-engine.aarch64 0:19.03.11.ol-13.el7
依存性関連をインストールしました:
container-selinux.noarch 2:2.119.2-1.911c772.el7_8 containerd.aarch64 0:1.4.8-1.el7 criu.aarch64 0:3.12-2.el7
docker-cli.aarch64 0:19.03.11.ol-13.el7 libnet.aarch64 0:1.1.6-7.el7 protobuf-c.aarch64 0:1.0.2-3.el7
runc.aarch64 3:1.0.0-1.rc95.el7
完了しました!
[opc@oracle01 ~]$ systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
Active: inactive (dead)
Docs: https://docs.docker.com
[opc@oracle01 ~]$ sudo systemctl start docker
[opc@oracle01 ~]$ sudo systemctl enable docker
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
[opc@oracle01 ~]$ sudo usermod -a -G docker $USER
[opc@oracle01 ~]$ sudo docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
次回のログイン以降は、opcユーザにてsudo権限なしでdockerコマンドが実行できます。
無事にインストールする事ができましたので、上記をもとにcloud-init.ymlを作成しました。
#cloud-config
# vim:syntax=yaml
runcmd:
- sudo yum install -y docker-engine
- sudo systemctl start docker
- sudo systemctl enable docker
- sudo usermod -a -G docker opc # $USERは使えませんでした
instance作成後にdockerが動いている事を確認します。
[opc@oracle01 ~]$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
RKE Terraform
kubernetesの構築ツールにはRKEを利用します。
terraformのリソースをそのまま使える、以下のrkeプロバイダでtfファイルを記載していきます。(GitHubを参照)
実際にterraform apply
すると成功し、kubernetesクラスタが構築されている事が確認できました。
[opc@oracle01 ~]$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ecb9dc05036c rancher/mirrored-coredns-coredns "/coredns -conf /etc…" 33 minutes ago Up 33 minutes k8s_coredns_coredns-55b58f978-nd6sr_kube-system_2c696135-88d5-4d57-a80d-575c7507004e_0
69efd7e2704b rancher/mirrored-nginx-ingress-controller-defaultbackend "/server-arm64" 33 minutes ago Up 33 minutes k8s_default-http-backend_default-http-backend-6977475d9b-bjc72_ingress-nginx_71be26d2-d8cf-4877-8005-81676346459e_0
c6f4259f6e91 rancher/mirrored-pause:3.2 "/pause" 33 minutes ago Up 33 minutes k8s_POD_coredns-55b58f978-nd6sr_kube-system_2c696135-88d5-4d57-a80d-575c7507004e_0
12bf3cc33185 rancher/mirrored-cluster-proportional-autoscaler "/cluster-proportion…" 33 minutes ago Up 33 minutes k8s_autoscaler_coredns-autoscaler-76f8869cc9-fz8jr_kube-system_6955d35e-c996-4264-ad43-e11fc4748baa_0
ecd0050bd189 rancher/nginx-ingress-controller "/usr/bin/dumb-init …" 33 minutes ago Up 33 minutes k8s_nginx-ingress-controller_nginx-ingress-controller-tpjtr_ingress-nginx_e1408e4a-8a29-423d-bd24-ba7fcad9da99_0
67e45b609e7d rancher/mirrored-pause:3.2 "/pause" 34 minutes ago Up 34 minutes k8s_POD_default-http-backend-6977475d9b-bjc72_ingress-nginx_71be26d2-d8cf-4877-8005-81676346459e_0
4e6be2c0e612 rancher/mirrored-pause:3.2 "/pause" 34 minutes ago Up 34 minutes k8s_POD_coredns-autoscaler-76f8869cc9-fz8jr_kube-system_6955d35e-c996-4264-ad43-e11fc4748baa_0
e65df82f92be rancher/flannel-cni "/install-cni.sh" 34 minutes ago Up 34 minutes k8s_install-cni_kube-flannel-pmfcn_kube-system_3deb1082-3668-4ee6-907d-5fc45ce48981_0
806aee5c3b8f rancher/mirrored-pause:3.2 "/pause" 34 minutes ago Up 34 minutes k8s_POD_nginx-ingress-controller-tpjtr_ingress-nginx_e1408e4a-8a29-423d-bd24-ba7fcad9da99_0
a5cf72cb48b8 rancher/coreos-flannel "/opt/bin/flanneld -…" 34 minutes ago Up 34 minutes k8s_kube-flannel_kube-flannel-pmfcn_kube-system_3deb1082-3668-4ee6-907d-5fc45ce48981_0
bc5985899526 rancher/mirrored-pause:3.2 "/pause" 34 minutes ago Up 34 minutes k8s_POD_kube-flannel-pmfcn_kube-system_3deb1082-3668-4ee6-907d-5fc45ce48981_0
7219c0d3886f rancher/hyperkube:v1.20.8-rancher1 "/opt/rke-tools/entr…" 35 minutes ago Up 35 minutes kube-proxy
3beaac0fd85a rancher/hyperkube:v1.20.8-rancher1 "/opt/rke-tools/entr…" 35 minutes ago Up 35 minutes kubelet
56f196ccf7d8 rancher/hyperkube:v1.20.8-rancher1 "/opt/rke-tools/entr…" 35 minutes ago Up 35 minutes kube-scheduler
b694deb67800 rancher/hyperkube:v1.20.8-rancher1 "/opt/rke-tools/entr…" 35 minutes ago Up 35 minutes kube-controller-manager
b31728e3221a rancher/hyperkube:v1.20.8-rancher1 "/opt/rke-tools/entr…" 35 minutes ago Up 35 minutes kube-apiserver
737801e8a25b rancher/rke-tools:v0.1.75 "/docker-entrypoint.…" 36 minutes ago Up 36 minutes etcd-rolling-snapshots
ed16cec534e9 rancher/mirrored-coreos-etcd:v3.4.15-rancher1 "/usr/local/bin/etcd…" 36 minutes ago Up 36 minutes etcd
ただし、local_file
を使ってkube_configを取得使用としましたが、実際には作られないようです。
$ terraform apply -auto-approve
# snip...
# local_file.kube_cluster_yaml will be created
+ resource "local_file" "kube_cluster_yaml" {
+ content = (sensitive)
+ directory_permission = "0777"
+ file_permission = "0777"
+ filename = "kube_config_cluster.yml"
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
local_file.kube_cluster_yaml: Creating...
local_file.kube_cluster_yaml: Creation complete after 0s [id=bc1d87d0049b08945c0404e75a0037271cfa831a]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
$ ls kube_cluster_yaml
ls: kube_cluster_yaml: No such file or directory
RKE Terraform
kubernetesの構築ツールにはRKEを利用します。
terraformのリソースをそのまま使える、以下のrkeプロバイダでtfファイルを記載していきます。(GitHubを参照)
実際にterraform apply
すると成功し、kubernetesクラスタが構築されている事が確認できました。
[opc@oracle01 ~]$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ecb9dc05036c rancher/mirrored-coredns-coredns "/coredns -conf /etc…" 33 minutes ago Up 33 minutes k8s_coredns_coredns-55b58f978-nd6sr_kube-system_2c696135-88d5-4d57-a80d-575c7507004e_0
69efd7e2704b rancher/mirrored-nginx-ingress-controller-defaultbackend "/server-arm64" 33 minutes ago Up 33 minutes k8s_default-http-backend_default-http-backend-6977475d9b-bjc72_ingress-nginx_71be26d2-d8cf-4877-8005-81676346459e_0
c6f4259f6e91 rancher/mirrored-pause:3.2 "/pause" 33 minutes ago Up 33 minutes k8s_POD_coredns-55b58f978-nd6sr_kube-system_2c696135-88d5-4d57-a80d-575c7507004e_0
12bf3cc33185 rancher/mirrored-cluster-proportional-autoscaler "/cluster-proportion…" 33 minutes ago Up 33 minutes k8s_autoscaler_coredns-autoscaler-76f8869cc9-fz8jr_kube-system_6955d35e-c996-4264-ad43-e11fc4748baa_0
ecd0050bd189 rancher/nginx-ingress-controller "/usr/bin/dumb-init …" 33 minutes ago Up 33 minutes k8s_nginx-ingress-controller_nginx-ingress-controller-tpjtr_ingress-nginx_e1408e4a-8a29-423d-bd24-ba7fcad9da99_0
67e45b609e7d rancher/mirrored-pause:3.2 "/pause" 34 minutes ago Up 34 minutes k8s_POD_default-http-backend-6977475d9b-bjc72_ingress-nginx_71be26d2-d8cf-4877-8005-81676346459e_0
4e6be2c0e612 rancher/mirrored-pause:3.2 "/pause" 34 minutes ago Up 34 minutes k8s_POD_coredns-autoscaler-76f8869cc9-fz8jr_kube-system_6955d35e-c996-4264-ad43-e11fc4748baa_0
e65df82f92be rancher/flannel-cni "/install-cni.sh" 34 minutes ago Up 34 minutes k8s_install-cni_kube-flannel-pmfcn_kube-system_3deb1082-3668-4ee6-907d-5fc45ce48981_0
806aee5c3b8f rancher/mirrored-pause:3.2 "/pause" 34 minutes ago Up 34 minutes k8s_POD_nginx-ingress-controller-tpjtr_ingress-nginx_e1408e4a-8a29-423d-bd24-ba7fcad9da99_0
a5cf72cb48b8 rancher/coreos-flannel "/opt/bin/flanneld -…" 34 minutes ago Up 34 minutes k8s_kube-flannel_kube-flannel-pmfcn_kube-system_3deb1082-3668-4ee6-907d-5fc45ce48981_0
bc5985899526 rancher/mirrored-pause:3.2 "/pause" 34 minutes ago Up 34 minutes k8s_POD_kube-flannel-pmfcn_kube-system_3deb1082-3668-4ee6-907d-5fc45ce48981_0
7219c0d3886f rancher/hyperkube:v1.20.8-rancher1 "/opt/rke-tools/entr…" 35 minutes ago Up 35 minutes kube-proxy
3beaac0fd85a rancher/hyperkube:v1.20.8-rancher1 "/opt/rke-tools/entr…" 35 minutes ago Up 35 minutes kubelet
56f196ccf7d8 rancher/hyperkube:v1.20.8-rancher1 "/opt/rke-tools/entr…" 35 minutes ago Up 35 minutes kube-scheduler
b694deb67800 rancher/hyperkube:v1.20.8-rancher1 "/opt/rke-tools/entr…" 35 minutes ago Up 35 minutes kube-controller-manager
b31728e3221a rancher/hyperkube:v1.20.8-rancher1 "/opt/rke-tools/entr…" 35 minutes ago Up 35 minutes kube-apiserver
737801e8a25b rancher/rke-tools:v0.1.75 "/docker-entrypoint.…" 36 minutes ago Up 36 minutes etcd-rolling-snapshots
ed16cec534e9 rancher/mirrored-coreos-etcd:v3.4.15-rancher1 "/usr/local/bin/etcd…" 36 minutes ago Up 36 minutes etcd
ただし、local_file
を使ってkube_configを取得使用としましたが、実際には作られないようです。
$ terraform apply -auto-approve
# snip...
# local_file.kube_cluster_yaml will be created
+ resource "local_file" "kube_cluster_yaml" {
+ content = (sensitive)
+ directory_permission = "0777"
+ file_permission = "0777"
+ filename = "kube_config_cluster.yml"
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
local_file.kube_cluster_yaml: Creating...
local_file.kube_cluster_yaml: Creation complete after 0s [id=bc1d87d0049b08945c0404e75a0037271cfa831a]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
$ ls kube_cluster_yaml
ls: kube_cluster_yaml: No such file or directory
本来であれば、kubectl --kubeconfig /path/to/config_yaml get nodes
のように使うので、現状kubectlコマンドが(簡単には)使えない事になります。
Kubernetes Provider
RKEにてk8sクラスタの構築は終わったので、TerraformのKubernetes Providerを使用してmanifestをapplyさせていきます。
provider "kubernetes" {
host = rke_cluster.cluster.api_server_url
username = rke_cluster.cluster.kube_admin_user
client_certificate = rke_cluster.cluster.client_cert
client_key = rke_cluster.cluster.client_key
cluster_ca_certificate = rke_cluster.cluster.ca_crt
}
resource "kubernetes_namespace" "example" {
metadata {
name = "my-first-namespace"
}
}
しかし、rke_clusterでbastionの設定をしていたのであっさりとエラーが出ました。
kubernetes_namespace.example: Creating...
kubernetes_namespace.example: Still creating... [10s elapsed]
kubernetes_namespace.example: Still creating... [20s elapsed]
kubernetes_namespace.example: Still creating... [30s elapsed]
╷
│ Error: Post "https://192.168.1.122:6443/api/v1/namespaces": dial tcp 192.168.1.122:6443: i/o timeout
│
│ with kubernetes_namespace.example,
│ on kubernetes.tf line 10, in resource "kubernetes_namespace" "example":
│ 10: resource "kubernetes_namespace" "example" {
│
╵
kubernetes providerにはbastion機能がないため、GitHub Actionsから直接k8sのAPIのエンドポイントを叩く事ができません。
案
- bastionのiptablesでportforwardingの設定を追加 <- このやり方を試してみます。
- DHCPなので名前解決が必要
- dns-utilsを入れる
- k8sクラスタが起動した後に実行する必要がある(bastion作成時にはIPアドレス付与されていないため)
- DHCPなので名前解決が必要
- OCI内部のホスト(bastionかk8s master node)でkubectlを実行する
- rkeからのリソースを渡しにくくなる
- kubernetes provider使えない
k8sクラスタ作成時に、bastionでiptablesを実行
-
k8sクラスタのinstance作成時に、terraform remote-execでbastionにSSHしてiptablesを実行しました
- この時、k8s masterノードのPrivateIPの情報を引き渡す事ができます。
-
この状態で再度実行します。
kubernetes_namespace.example: Creating...
╷
│ Error: Post "https://140.238.54.52:6443/api/v1/namespaces": x509: certificate is valid for 192.168.1.25, 127.0.0.1, 10.43.0.1, not 140.238.54.52
│
│ with kubernetes_namespace.example,
│ on kubernetes.tf line 9, in resource "kubernetes_namespace" "example":
│ 9: resource "kubernetes_namespace" "example" {
│
╵
今度は証明書のが有効でないのでAPIが叩けませんでした。
証明書を自作して、PublicIPからのアクセスを許可すれば通りそうですが、
それ以外にも問題があったので、いったんこの構成の検証はここまでにします。
構成変更
構成変更に至ったきっかけ
always freeプランで無料で使う事が前提ですが、課金プランに登録しました。
それにより、少しだけ認識が間違っていたので料金が発生してしまったり、、制約が緩くなったものもあるので、これをきっかけに構成変更します。
- Block Volumeのfreeで使える容量の認識を誤っていた
- 合計で200GB
- 1 instanceには自動で50GB使用される
- つまり無料で使用できるinstanceは4つまで -> bastion廃止
- Ubuntu20.04が使用できないと勘違いしていた
- (あまりよく知らない)Oracle Linuxで代用していた
- minimalは使用できないが、普通のものは使える
- PublicIPを使用できる数が増えた
- 課金プランに変更した(使用するのは無料分だけなので、もちろん無料)
- 各instanceにPublicIPを割り当てられる
料金表は以下に載っています。
新しい構成
- Public Subnetにkubernetesクラスタを全て置く
- kubernetesクラスタは全てエフェメラルPublicIPを持つ
- bastionは使用しない
terraform provider rke
以下のように、nodeのaddressをPublicIPに設定します。
resource "rke_cluster" "cluster" {
nodes {
address = oci_core_instance.kubernetes.0.public_ip # instance作成時に指定したリソース名
internal_address = oci_core_instance.kubernetes.0.private_ip # instance作成時に指定したリソース名
user = "ubuntu"
ssh_key = var.PRIVATE_KEY_INSTANCE
role = ["controlplane", "worker", "etcd"]
}
この状態でterraform applyしましたが、以下のエラーに
│ time="2021-07-31T13:02:55Z" level=info msg="[controlplane] Successfully started Controller Plane.."
│ time="2021-07-31T13:02:55Z" level=info msg="[authz] Creating rke-job-deployer ServiceAccount"
│
│ Failed running cluster err:Failed to apply the ServiceAccount needed for job execution: Post "https://132.226.8.71:6443/apis/rbac.authorization.k8s.io/v1/clusterrolebindings?timeout=30s": dial tcp 132.226.8.71:6443: connect: no route to host
│ ========================================
実際にinstanceにログインしてcurlを叩いてみると、確かにno route to hostと返ってきます。
デフォルトでiptablesに設定が入っていたため、iptablesは全て削除してからリトライします。
sudo iptables -F
次のエラー
│
│ Failed running cluster err:[network] Can't access KubeAPI port [6443] on Control Plane host: 132.226.8.71
│ ========================================
│
│
│ with rke_cluster.cluster,
│ on rke_cluster.tf line 7, in resource "rke_cluster" "cluster":
│ 7: resource "rke_cluster" "cluster" {
│
╵
instanceにログインして確認すると、実際にはconnection timeoutとなってしまいます。
疎通も取れて、sshも出来ています。。
$ curl 132.226.8.71:6443
curl: (28) Failed to connect to 132.226.8.71 port 6443: Connection timed out
$ ping 132.226.8.71
PING 132.226.8.71 (132.226.8.71) 56(84) bytes of data.
64 bytes from 132.226.8.71: icmp_seq=1 ttl=63 time=0.219 ms
$ ssh 132.226.8.71 "hostname"
ubuntu01
セキュリティールールでは、egress,ingress共に6443を許可していますが、試しにセキュリティルールを全て許可してリトライしてみます。また、iptablesに以下の設定を追加して、内部からPublicIPにAPIを投げるときに、PrivateIPになるようにアドレスを変換しました。
# PublicIP(132.226.10.44)をPrivateIP(192.168.0.211)に変換する
sudo iptables -t nat -A OUTPUT -d 132.226.10.44 -j DNAT --to-destination 192.168.0.211
リトライしましたが、同様のエラーとなってしまいました。
実際にinstanceにログインしてcurlを叩いてみると、アドレス変換は行われているようでアクセスできました。
ubuntu@ubuntu01:~$ curl https://132.226.10.44:6443
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 132.226.10.44:6443
しかしながら、instance外部からAPIを実行してみると、timeoutしてしまいます。
どうやらrkeでクラスタを構築するときは、外部からAPIで通信できる必要がありそうです。
iptablesの設定と、セキュリティールールの設定は全てoffにしておりますが、
おそらくOracle Cloud側で制御されていそうな気がしますが、もう少し調査してみます。
instanceの調査
まずは、nginxのdockerをinstanceの80 Portで公開します。
ubuntu@ubuntu01:~$ docker run -d --rm -p 80:80 nginx:alpine
Unable to find image 'nginx:alpine' locally
alpine: Pulling from library/nginx
fd3acdcea568: Pull complete
c1670e91f443: Pull complete
7fdac1642bfa: Pull complete
1394476d63eb: Pull complete
ad901a1137d5: Pull complete
fe0fe785c479: Pull complete
Digest: sha256:bead42240255ae1485653a956ef41c9e458eb077fcb6dc664cbc3aa9701a05ce
Status: Downloaded newer image for nginx:alpine
f62a20c8b82ebb29580c358d63cd9989988909c9c67e8d37511c2bcdc8b4a246
ubuntu@ubuntu01:~$ ss -antu | grep 0.0.0.0:80
tcp LISTEN 0 4096 0.0.0.0:80 0.0.0.0:*
ubuntu@ubuntu01:~$ curl localhost:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
無事に起動できており、localhostでアクセスできる事が確認できます。
次に、instance外部からこのPublicIP:80にアクセスできるか確認してみます。
$ curl http://132.226.10.44:80
curl: (7) Failed to connect to 132.226.10.44 port 80: Operation timed out
timeoutが返ってきました。
どうやら、instance側のiptables設定がよろしくなさそうなので、もう一度正しくiptablesなどの設定します。クラスタ作成に必要なポートは、以下のrancherドキュメントに載っています。
ブリッジを通過するトラフィックの処理を許可します。
sudo sysctl -w net.bridge.bridge-nf-call-iptables=1
iptablesの設定をします。
とりあえず、instance側のデフォルトの設定は全てACCEPTにします。
(必要あればセキュリティーリスト側で制御しようと思います。)
sudo iptables -F
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo netfilter-persistent save
以上でリトライしてみます。
local_file.kube_cluster_yaml: Creating...
local_file.kube_cluster_yaml: Creation complete after 0s [id=b66d01bef1609dcdf6255eb34578a8348a513dad]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
クラスタ作成する事ができました!!
ただ、local_fileでkubeconfigのymlが作成される設定にしていますが、作成されていないようです。
(PublicIPのクラスタを作成する場合は、local_fileで作成できないのでしょうか、、、)
kubernetesリソースの作成
以下のようなHCIを用意して、terraform applyします。
provider "kubernetes" {
host = rke_cluster.cluster.api_server_url
username = rke_cluster.cluster.kube_admin_user
client_certificate = rke_cluster.cluster.client_cert
client_key = rke_cluster.cluster.client_key
cluster_ca_certificate = rke_cluster.cluster.ca_crt
}
resource "kubernetes_namespace" "example" {
metadata {
name = "my-first-namespace"
}
}
kuberctl
が使えないので、etcdで見てみます。
ubuntu@ubuntu01:~$ docker container ls | grep etcd
41be522b5ed9 rancher/rke-tools:v0.1.75 "/docker-entrypoint.…" 13 minutes ago Up 13 minutes etcd-rolling-snapshots
4fd1a3a6df0b rancher/mirrored-coreos-etcd:v3.4.15-rancher1 "/usr/local/bin/etcd…" 13 minutes ago Up 13 minutes etcd
ubuntu@ubuntu01:~$ docker container exec -it 4fd1 sh
# etcdctl get / --prefix --keys-only | grep my-first-namespace
/registry/configmaps/my-first-namespace/kube-root-ca.crt
/registry/namespaces/my-first-namespace
/registry/secrets/my-first-namespace/default-token-g4rtz
/registry/serviceaccounts/my-first-namespace/default
とりあえず、無事に作られてはいそうでした。
kubectl
が使えないのがしんどいですが、kubernetesリソースもterraform管理して運用していきたいと思います。
冪等性について
2回目にterraform applyすると、kubernetesのリソースで以下のエラーになりました。
╷
│ Error: Get "http://localhost/api/v1/namespaces/my-first-namespace": dial tcp 127.0.0.1:80: connect: connection refused
│
│ with kubernetes_namespace.example,
│ on kubernetes.tf line 9, in resource "kubernetes_namespace" "example":
│ 9: resource "kubernetes_namespace" "example" {
│
╵
おそらく、rke_clusterのtfstateがうまく保持できていないからだと思います。
terraform state rm で強制的にkubenetes_namespaceを削除して、再実行してみると
kubernetes_namespace.example: Creating...
╷
│ Error: namespaces "my-first-namespace" already exists
│
│ with kubernetes_namespace.example,
│ on kubernetes.tf line 9, in resource "kubernetes_namespace" "example":
│ 9: resource "kubernetes_namespace" "example" {
│
tfstateだけ削除しても、kubenetesにはリソースがいると怒られてしまいました。
後で気づきましたが、このnamespaceを消すためには、tfファイルの記載を削除してterraform applyする必要がありました。
kubectl
の導入
local_fileで作成されないのは、おそらくterraformの実行先をterraform cloudにしており、API drivenで実行している事が関係していると思います。(多分)
またkubectl
が使えなくとも、kubeconfigが参照できないのはしんどいので、以下を実施することにしました。
- masterにkubectlをインストール
- masterに
~./kube/config
を配置
terraform rke_clusterのtfファイルに、以下のprovisionerを追記しました。
provisioner "remote-exec" {
connection {
type = "ssh"
user = "ubuntu"
host = oci_core_instance.kubernetes.0.public_ip
private_key = var.PRIVATE_KEY_INSTANCE
}
scripts = [
"provisioning/install-kubectl.sh",
]
}
provisioner "file" {
connection {
type = "ssh"
user = "ubuntu"
host = oci_core_instance.kubernetes.0.public_ip
private_key = var.PRIVATE_KEY_INSTANCE
}
content = rke_cluster.cluster.kube_config_yaml
destination = "~/.kube/config"
}
install-kubectl.sh
の中身は以下のようになっており、バイナリ形式でインストールしてます。
curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/arm64/kubectl" # arm64に設定
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
mkdir -p ~/.kube # 最後に~/.kubeディレクトリを作成して、後続のfile provisionerで~/.kube/configを配置できるようにしています。
無事にrke_clusterが完了したので、instanceにログインしてkubectl
を実行してみます。
ubuntu@ubuntu01:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
152.70.98.146 Ready controlplane,etcd,worker 83s v1.20.8
168.138.199.247 Ready worker 80s v1.20.8
無事にkubectlを実行する事ができました。
上記で管理できたため Close します。
次は、以下のようなことを検証したいと思います。
- kubernetes の manifest をどのように運用するか
- HCL or yaml(argocdなど)
- ingress 導入時の LoadBalancer 作成