入門 vcluster
What's vcluster
今回ご紹介させていただくのは、Virtual Clusters For Kubernetesを実現するvclusterです!
既存のkubernetes上で簡単に仮想的なkubernetes clusterを構築することができます。
Architecture
Basics | vcluster docs | Virtual Clusters for Kubernetes
主なコンポーネントとしては以下の2つです。
以下のコンポーネントは、stateful-setによってスケジューリングされるpodの中に2つのコンテナとして作成されます。
- control-plane:
- syncer:
- vcluster上のPod等のリソースは、ホストクラスター上でcontrol-planeを展開したNamespace上に集約されます。syncerはその仮想cluster上のポッドとhost cluster上のポッドの同期を維持します。
Installation
Download vcluster CLI
まず、vcluster cli
を導入していきます。
# curl -s -L "https://github.com/loft-sh/vcluster/releases/latest" | sed -nE 's!.*"([^"]*vcluster-linux-amd64)".*!https://github.com\1!p' | xargs -n 1 curl -L -o vcluster && chmod +x vcluster; sudo mv vcluster /usr/local/bin;
Create a vcluster
準備はこれだけです。 では、以下のコマンドを実行しましょう。
※ こちらを用いる際、helmをインストールしておいてください。
# vcluster create vcluster-1 -n vcluster-system
kubectlでインストールする場合は、こちらのmanifestを利用してください。
▸ vcluster.yaml (clickして展開)
apiVersion: v1 kind: ServiceAccount metadata: name: vcluster-1 --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: vcluster-1 rules: - apiGroups: [""] resources: ["configmaps", "secrets", "services", "services/proxy", "pods", "pods/proxy", "pods/attach", "pods/portforward", "pods/exec", "pods/log", "events", "endpoints", "persistentvolumeclaims"] verbs: ["*"] - apiGroups: ["networking.k8s.io"] resources: ["ingresses"] verbs: ["*"] - apiGroups: [""] resources: ["namespaces"] verbs: ["get", "list", "watch"] - apiGroups: ["apps"] resources: ["statefulsets"] verbs: ["get", "list", "watch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: vcluster-1 subjects: - kind: ServiceAccount name: vcluster-1 roleRef: kind: Role name: vcluster-1 apiGroup: rbac.authorization.k8s.io --- apiVersion: v1 kind: Service metadata: name: vcluster-1 spec: type: ClusterIP ports: - name: https port: 443 targetPort: 8443 protocol: TCP selector: app: vcluster-1 --- apiVersion: v1 kind: Service metadata: name: vcluster-1-headless spec: ports: - name: https port: 443 targetPort: 8443 protocol: TCP clusterIP: None selector: app: vcluster-1 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: vcluster-1 labels: app: vcluster-1 spec: serviceName: vcluster-1-headless replicas: 1 selector: matchLabels: app: vcluster-1 template: metadata: labels: app: vcluster-1 spec: terminationGracePeriodSeconds: 10 serviceAccountName: vcluster-1 containers: - image: rancher/k3s:v1.19.5-k3s2 name: virtual-cluster command: - "/bin/k3s" args: - "server" - "--write-kubeconfig=/k3s-config/kube-config.yaml" - "--data-dir=/data" - "--disable=traefik,servicelb,metrics-server,local-storage" - "--disable-network-policy" - "--disable-agent" - "--disable-scheduler" - "--disable-cloud-controller" - "--flannel-backend=none" - "--kube-controller-manager-arg=controllers=*,-nodeipam,-nodelifecycle,-persistentvolume-binder,-attachdetach,-persistentvolume-expander,-cloud-node-lifecycle" - "--service-cidr=10.96.0.0/12" volumeMounts: - mountPath: /data name: data - name: syncer image: "loftsh/virtual-cluster:0.0.27" args: - --service-name=vcluster-1 - --suffix=vcluster-1 - --owning-statefulset=vcluster-1 - --out-kube-config-secret=vcluster-1 volumeMounts: - mountPath: /data name: data volumeClaimTemplates: - metadata: name: data spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 5Gi
namespaceを作成してからapplyしていきます。
# kubectl create ns vcluster-system namespace/vcluster-system created # kubectl apply -f vcluster.yaml -n vcluster-system serviceaccount/vcluster-1 created role.rbac.authorization.k8s.io/vcluster-1 created rolebinding.rbac.authorization.k8s.io/vcluster-1 created service/vcluster-1 created service/vcluster-1-headless created statefulset.apps/vcluster-1 created
では、リソースができているか確認していきます。
# kubectl get pods,svc -n vcluster-system -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/coredns-66c464876b-98ln7-x-kube-system-x-vcluster-1 1/1 Running 0 42h 172.17.0.4 minikube.mydom.local <none> <none> pod/vcluster-1-0 2/2 Running 1 42h 172.17.0.3 minikube.mydom.local <none> <none> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service/kube-dns-x-kube-system-x-vcluster-1 ClusterIP 10.107.141.148 <none> 53/UDP,53/TCP,9153/TCP 42h <none> service/vcluster-1 ClusterIP 10.96.161.85 <none> 443/TCP 42h app=vcluster-1 service/vcluster-1-headless ClusterIP None <none> 443/TCP 42h app=vcluster-1
Connect to the cluster
では接続していきたいと思います。
# vcluster connect vcluster-1 -n vcluster-system --local-port 9443 --kube-config vcluster.yaml & [1] 9589 [done] √ Virtual cluster kube config written to: ./kubeconfig.yaml. You can access the cluster via `kubectl --kubeconfig ./kubeconfig.yaml get namespaces` [info] Starting port forwarding: kubectl port-forward --namespace vcluster-system vcluster-1-0 9443:8443 Forwarding from 127.0.0.1:9443 -> 8443
見ていただければわかると思いますが、裏で kubectl port-forward
をしています。
以下のようなルールで書きます。
vcluster connect [cluster名] -n [control-planeがいるnamespace] --local-port [port-forwardするlocal port] --kube-config <kubeconfig ファイル名> &
では、実際に仮想clusterに接続していきます。
# kubectl get namespace --kubeconfig vcluster.yaml Handling connection for 9443 NAME STATUS AGE default Active 43h kube-system Active 43h kube-public Active 43h kube-node-lease Active 43h
先ほど作成した、vcluster-system
namespaceは見えてきてないですね!
Create resources
では、実際にリソースを作成していきたいと思います。
まずnamespaceを作成していきます。
# kubectl create ns demo1 --kubeconfig vcluster.yaml
仮想clusterでは作成され、host cluster側には当然見えてきてないです。
/// host cluster # kubectl get ns NAME STATUS AGE default Active 119d kube-node-lease Active 119d kube-public Active 119d kube-system Active 119d vcluster-system Active 2d /// 仮想cluster # kubectl get ns --kubeconfig vcluster.yaml NAME STATUS AGE default Active 2d kube-system Active 2d kube-public Active 2d kube-node-lease Active 2d demo1 Active 93m
では、default
と demo1
の2つのnamespaceにリソースを作成していきます。
kubectl create deploy nginx --image=nginx:1.19.5 --replicas=5 --kubeconfig vcluster.yaml kubectl create deploy nginx --image=nginx:1.19.5 --replicas=3 -n demo1 --kubeconfig vcluster.yaml
以下の通り作成されました。
# kubectl get pods -n default -n default --kubeconfig vcluster.yaml NAME READY STATUS RESTARTS AGE nginx-7c4b6d99fd-sjnh2 1/1 Running 0 89m nginx-7c4b6d99fd-r2rsh 1/1 Running 0 89m nginx-7c4b6d99fd-7z6wx 1/1 Running 0 89m nginx-7c4b6d99fd-4srv2 1/1 Running 0 89m nginx-7c4b6d99fd-m5t62 1/1 Running 0 89m # kubectl get pods -n default -n demo1 --kubeconfig vcluster.yaml NAME READY STATUS RESTARTS AGE nginx-7c4b6d99fd-v67kb 1/1 Running 0 89m nginx-7c4b6d99fd-wwswz 1/1 Running 0 89m nginx-7c4b6d99fd-lbjdw 1/1 Running 0 89m
では、host clusterではどう見えているのか確認してみましょう。
# kubectl get pod -n vcluster-system NAME READY STATUS RESTARTS AGE coredns-66c464876b-98ln7-x-kube-system-x-vcluster-1 1/1 Running 0 2d nginx-7c4b6d99fd-4srv2-x-default-x-vcluster-1 1/1 Running 0 95m nginx-7c4b6d99fd-7z6wx-x-default-x-vcluster-1 1/1 Running 0 95m nginx-7c4b6d99fd-lbjdw-x-demo1-x-vcluster-1 1/1 Running 0 95m nginx-7c4b6d99fd-m5t62-x-default-x-vcluster-1 1/1 Running 0 95m nginx-7c4b6d99fd-r2rsh-x-default-x-vcluster-1 1/1 Running 0 95m nginx-7c4b6d99fd-sjnh2-x-default-x-vcluster-1 1/1 Running 0 95m nginx-7c4b6d99fd-v67kb-x-demo1-x-vcluster-1 1/1 Running 0 95m nginx-7c4b6d99fd-wwswz-x-demo1-x-vcluster-1 1/1 Running 0 95m vcluster-1-0 2/2 Running 1 2d
最初の方に説明した通り、仮想clusterで作成されたリソースが、control-planeのいるnamespaceに集約されていることがわかるかと思います。
[pod名]-x-[namespace名]-x-[vcluster名]
という規則で作成されていることがわかります。
etc...
その他のリソースもどうなっているのか見ていきましょう。
service
サービスもPodと同様な規則でhost cluster側では見えてきます。
/// host cluster # kubectl get service -n vcluster-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns-x-kube-system-x-vcluster-1 ClusterIP 10.107.141.148 <none> 53/UDP,53/TCP,9153/TCP 47h vcluster-1 ClusterIP 10.96.161.85 <none> 443/TCP 47h vcluster-1-headless ClusterIP None <none> 443/TCP 47h /// 仮想cluster # kubectl get service -A --kubeconfig vcluster.yaml Handling connection for 9443 NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE default kubernetes ClusterIP 10.96.161.85 <none> 443/TCP 47h kube-system kube-dns ClusterIP 10.107.141.148 <none> 53/UDP,53/TCP,9153/TCP 47h
Service Account
こちらは、Ageが違うので同期はされてなさそうです。
/// host cluster # kubectl get sa -A NAMESPACE NAME SECRETS AGE default default 1 119d host-namespace-1 default 1 47h kube-node-lease default 1 119d kube-public default 1 119d kube-system attachdetach-controller 1 119d kube-system bootstrap-signer 1 119d kube-system certificate-controller 1 119d kube-system clusterrole-aggregation-controller 1 119d kube-system coredns 1 119d kube-system cronjob-controller 1 119d kube-system daemon-set-controller 1 119d kube-system default 1 119d kube-system deployment-controller 1 119d kube-system disruption-controller 1 119d kube-system endpoint-controller 1 119d kube-system endpointslice-controller 1 119d kube-system endpointslicemirroring-controller 1 119d kube-system expand-controller 1 119d kube-system generic-garbage-collector 1 119d kube-system horizontal-pod-autoscaler 1 119d kube-system job-controller 1 119d kube-system kube-proxy 1 119d kube-system namespace-controller 1 119d kube-system node-controller 1 119d kube-system persistent-volume-binder 1 119d kube-system pod-garbage-collector 1 119d kube-system pv-protection-controller 1 119d kube-system pvc-protection-controller 1 119d kube-system replicaset-controller 1 119d kube-system replication-controller 1 119d kube-system resourcequota-controller 1 119d kube-system root-ca-cert-publisher 1 119d kube-system service-account-controller 1 119d kube-system service-controller 1 119d kube-system statefulset-controller 1 119d kube-system storage-provisioner 1 119d kube-system token-cleaner 1 119d kube-system ttl-controller 1 119d vcluster-system default 1 47h vcluster-system vcluster-1 1 47h /// 仮想cluster # kubectl get sa -A --kubeconfig vcluster.yaml NAMESPACE NAME SECRETS AGE kube-system pv-protection-controller 1 47h kube-system endpoint-controller 1 47h kube-system daemon-set-controller 1 47h kube-system coredns 1 47h kube-system service-controller 1 47h kube-system job-controller 1 47h kube-system disruption-controller 1 47h kube-system certificate-controller 1 47h kube-system clusterrole-aggregation-controller 1 47h kube-system pvc-protection-controller 1 47h kube-system endpointslice-controller 1 47h kube-system replication-controller 1 47h kube-system resourcequota-controller 1 47h kube-system namespace-controller 1 47h kube-system horizontal-pod-autoscaler 1 47h kube-system statefulset-controller 1 47h kube-system pod-garbage-collector 1 47h kube-system deployment-controller 1 47h kube-system cronjob-controller 1 47h kube-system ttl-controller 1 47h kube-system endpointslicemirroring-controller 1 47h kube-system service-account-controller 1 47h kube-system generic-garbage-collector 1 47h kube-system replicaset-controller 1 47h kube-system default 1 47h kube-public default 1 47h default default 1 47h kube-node-lease default 1 47h demo1 default 1 7m19s
Node
Nodeは面白くて、Fake Kubernetes Image
というOS Imageを使ってるというように表記されてます。
# kubectl get node -A --kubeconfig vcluster.yaml -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME minikube.mydom.local Ready <none> 47h v1.19.1 192.124.212.254 <none> Fake Kubernetes Image 4.19.76-fakelinux docker://19.3.12 # kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME minikube.mydom.local Ready control-plane,master 119d v1.20.0 [node IP] <none> CentOS Linux 7 (Core) 3.10.0-957.el7.x86_64 docker://20.10.2
終わりに
一つのnamespaceに集約できるので、Resource Quotaを用いて簡単に、リソース制御ができるのはいいですね!
デモ環境を渡してあげたりとかが簡単にできると思うので、ぜひ使ってみてください。