W tej części zajmiemy się skonfigurowaniem sieci na naszym klastrze oraz sterownika do tworzenia volumenów. Zostanie stworzony obiekt StorageClass, który automatycznie utworzy wolumeny, kiedy będą potrzebne.
Zaczynamy od utworzenia pływającego IP (floating-ip). To IP w przyszłości będzie używane jako publiczne IP naszego klastra.
hcloud floating-ip create --type ipv4 --home-location fsn1
Następnie musimy utworzyć „sekret” zawierający nasz token, który został przez nas utworzony w części 1. Posłuży on do utworzenia Cloud Controller Manager, który połączy nasz klaster przez Hetzner API. Network_id można uzyskać przez wykonanie polecenia:
NETWORK_ID=$(hcloud network list -o noheader -o columns=id)
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: hcloud
namespace: kube-system
stringData:
token: $HCLOUD_TOKEN
network: "$NETWORK_ID"
EOF
Potem musimy jeszcze doinstalować wspomnianego wcześniej Cloud Controller Manager. Robimy to za pomocą polecenia:
kubectl apply -f https://raw.githubusercontent.com/hetznercloud/hcloud-cloud-controller-manager/master/deploy/ccm.yaml
Następnie wykorzystamy test od Cilium, który przetestuje komunikację w różny sposób pomiędzy podami. Jeżeli wszystko jest skonfigurowane poprawnie, każdy z testów powinien zadziałać. Wykonujemy polecenie i czekamy parę minut, obserwując, jak kolejne pody zaczynają działać.
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/master/examples/kubernetes/connectivity-check/connectivity-check.yaml
$ kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
echo-a-dc9bcfd8f-mhbk2 1/1 Running 0 64s 10.0.2.123 worker-1 <none> <none>
echo-b-5884b7dc69-jwc6q 1/1 Running 0 64s 10.0.2.220 worker-1 <none> <none>
echo-b-host-cfdd57978-cwdr7 1/1 Running 0 64s 168.119.96.200 worker-1 <none> <none>
host-to-b-multi-node-clusterip-c4ff7ff64-k2677 1/1 Running 0 63s 78.46.206.239 worker-2 <none> <none>
host-to-b-multi-node-headless-84d8f6f4c4-zmq8h 1/1 Running 0 63s 78.46.206.239 worker-2 <none> <none>
pod-to-a-5cdfd4754d-vkmsp 1/1 Running 0 64s 10.0.1.161 worker-2 <none> <none>
pod-to-a-allowed-cnp-7d7c8f9f9b-bd89g 1/1 Running 0 63s 10.0.1.133 worker-2 <none> <none>
pod-to-a-denied-cnp-75cb89dfd-nhtfp 1/1 Running 0 63s 10.0.2.106 worker-1 <none> <none>
pod-to-b-intra-node-nodeport-99b499f7d-jrkk9 1/1 Running 0 62s 10.0.2.9 worker-1 <none> <none>
pod-to-b-multi-node-clusterip-cd4d764b6-cn7cz 1/1 Running 0 63s 10.0.1.225 worker-2 <none> <none>
pod-to-b-multi-node-headless-6696c5f8cd-qrn54 1/1 Running 0 63s 10.0.1.117 worker-2 <none> <none>
pod-to-b-multi-node-nodeport-7ff5595558-trhpp 1/1 Running 0 62s 10.0.1.72 worker-2 <none> <none>
pod-to-external-1111-d5c7bb4c4-wzwdc 1/1 Running 0 64s 10.0.1.57 worker-2 <none> <none>
pod-to-external-fqdn-allow-google-cnp-f48574954-dhtsc 1/1 Running 0 63s 10.0.2.206 worker-1 <none> <none>
Jak możemy zaobserwować, pody są utworzone i działają. Mają przypisane IP i są hostowane na jednym z 2 worker nodów. Nie było aż tak ciężko, prawda? Po zakończeniu testu możemy go usunąć poleceniem:
kubectl delete -f https://raw.githubusercontent.com/cilium/cilium/master/examples/kubernetes/connectivity-check/connectivity-check.yaml
$ kubectl create deploy nginx --image=nginx --replicas=10
deployment.apps/nginx created
$ kubectl get deploy,po
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/nginx 10/10 10 10 3m34s nginx nginx app=nginx
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/nginx-6799fc88d8-7jcd7 1/1 Running 0 3m33s 10.244.1.4 worker-1 <none> <none>
pod/nginx-6799fc88d8-brm6t 1/1 Running 0 3m34s 10.244.1.6 worker-1 <none> <none>
pod/nginx-6799fc88d8-cxcwh 1/1 Running 0 3m34s 10.244.2.4 worker-2 <none> <none>
pod/nginx-6799fc88d8-g7m9j 1/1 Running 0 3m34s 10.244.1.2 worker-1 <none> <none>
pod/nginx-6799fc88d8-jxd6m 1/1 Running 0 3m34s 10.244.2.5 worker-2 <none> <none>
pod/nginx-6799fc88d8-lmn7w 1/1 Running 0 3m34s 10.244.1.3 worker-1 <none> <none>
pod/nginx-6799fc88d8-s4r5t 1/1 Running 0 3m33s 10.244.2.3 worker-2 <none> <none>
pod/nginx-6799fc88d8-vbsmn 1/1 Running 0 3m34s 10.244.1.5 worker-1 <none> <none>
pod/nginx-6799fc88d8-vdxtp 1/1 Running 0 3m33s 10.244.2.6 worker-2 <none> <none>
pod/nginx-6799fc88d8-vm8j4 1/1 Running 0 3m34s 10.244.2.2 worker-2 <none> <none>
Ostatnim punktem konfiguracji klastra jest zaimplementowanie CSI, czyli Container Storage Interface. Oczywiście firma Hetzner dostarcza własną implementację tego interfejsu. Pozwoli ona utworzyć wirtualne dyski w firmie Hetzner, widoczne w Kubernetes jako wolumeny. Ponownie zaczynamy od utworzenia sekretu zawierającego nasz token.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: hcloud-csi
namespace: kube-system
stringData:
token: $HCLOUD_TOKEN
EOF
A następnie instalujemy implementację CSI z firmy Hetzner.
kubectl apply -f https://raw.githubusercontent.com/kubernetes/csi-api/release-1.14/pkg/crd/manifests/csidriver.yaml && \
kubectl apply -f https://raw.githubusercontent.com/kubernetes/csi-api/release-1.14/pkg/crd/manifests/csinodeinfo.yaml && \
kubectl apply -f https://raw.githubusercontent.com/hetznercloud/csi-driver/master/deploy/kubernetes/hcloud-csi.yml
Po chwili pody CSI działają. Mamy też skonfigurowany domyślny StorageClass, tworzący wolumeny, kiedy są potrzebne.
$ kubectl get po -n kube-system | grep csi
hcloud-csi-controller-0 4/4 Running 0 31s
hcloud-csi-node-mgx59 2/2 Running 0 31s
hcloud-csi-node-wmssb 2/2 Running 0 31s
$ kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
hcloud-volumes (default) csi.hetzner.cloud Delete WaitForFirstConsumer true 3m5s
Aby sprawdzić, czy wszystko działa, tworzymy pod z podpiętym wolumenem.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: csi-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: hcloud-volumes
---
kind: Pod
apiVersion: v1
metadata:
name: my-csi-app
spec:
containers:
- name: my-frontend
image: busybox
volumeMounts:
- mountPath: "/data"
name: my-csi-volume
command: [ "sleep", "1000000" ]
volumes:
- name: my-csi-volume
persistentVolumeClaim:
claimName: csi-pvc
EOF
Po chwili widzimy, że pod działa, a wolumen został utworzony automatycznie. Tę samą informację znajdziemy w konsoli Hetzner.
$ kubectl get po,pvc,pv
NAME READY STATUS RESTARTS AGE
pod/my-csi-app 1/1 Running 0 32s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/csi-pvc Bound pvc-9648fb6b-c22a-43bc-8d26-5720b428a9fe 10Gi RWO hcloud-volumes 32s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-9648fb6b-c22a-43bc-8d26-5720b428a9fe 10Gi RWO Delete Bound default/csi-pvc hcloud-volumes 29s
$ hcloud volume list
ID NAME SIZE SERVER LOCATION
8178835 pvc-9648fb6b-c22a-43bc-8d26-5720b428a9fe 10 GB worker-2 fsn1
Po usunięciu poda oraz persistentVolumeClaim nasz wolumen zostanie automatycznie usunięty (tak jest domyślnie skonfigurowany StorageClass).
Na dziś to już wszystko. W kolejnym wpisie skonfigurujemy prawdziwą aplikację, skonfigurujmy dla niej domenę oraz ustawimy automatycznie odnawialny certyfikat SSL z wykorzystaniem Let’s Encrypt. Daj znać w komentarzu czy i u Ciebie wszystko działa tak, jak powinno.
0 komentarzy