Kubernet Berdaya maju Minimum

Terjemahan artikel telah disediakan pada malam permulaan kursus "Amalan dan alatan DevOps".

Kubernet Berdaya maju Minimum

Jika anda membaca ini, anda mungkin pernah mendengar sesuatu tentang Kubernetes (dan jika tidak, bagaimanakah anda berada di sini?) Tetapi apakah sebenarnya Kubernetes itu? ini β€œOrkestrasi kontena gred industri”? Ataupun "Sistem Pengendalian Cloud-Native"? Apakah maksudnya ini?

Sejujurnya, saya tidak pasti 100%. Tetapi saya rasa menarik untuk menyelidiki bahagian dalaman dan melihat apa yang sebenarnya berlaku di Kubernetes di bawah banyak lapisan abstraksinya. Jadi hanya untuk keseronokan, mari kita lihat bagaimana sebenarnya "kelompok Kubernetes" yang minimum. (Ini akan menjadi lebih mudah daripada Kubernetes The Hard Way.)

Saya menganggap anda mempunyai pengetahuan asas tentang Kubernetes, Linux dan bekas. Semua yang kita bincangkan di sini adalah untuk tujuan penyelidikan/pembelajaran sahaja, jangan masukkan apa-apa ke dalam pengeluaran!

Mengkaji

Kubernetes mengandungi banyak komponen. mengikut Wikipedia, seni bina kelihatan seperti ini:

Kubernet Berdaya maju Minimum

Terdapat sekurang-kurangnya lapan komponen yang ditunjukkan di sini, tetapi kami akan mengabaikan kebanyakannya. Saya ingin menyatakan bahawa perkara minimum yang boleh dipanggil Kubernetes secara munasabah terdiri daripada tiga komponen utama:

  • cubelet
  • kube-apiserver (yang bergantung pada etcd - pangkalan datanya)
  • masa larian kontena (Docker dalam kes ini)

Mari lihat apa yang dikatakan dokumentasi tentang setiap daripada mereka (rus., Bahasa Inggeris.). Pada mulanya cubelet:

Ejen yang berjalan pada setiap nod dalam kelompok. Ia memastikan bahawa bekas berjalan di dalam pod.

Bunyi cukup mudah. Bagaimana pula masa jalan kontena (masa jalan kontena)?

Masa jalan kontena ialah program yang direka untuk menjalankan kontena.

Sangat bermaklumat. Tetapi jika anda sudah biasa dengan Docker, maka anda harus mempunyai idea umum tentang apa yang dilakukannya. (Butiran pemisahan tanggungjawab antara masa jalan kontena dan kubelet sebenarnya agak halus dan saya tidak akan membincangkannya di sini.)

И pelayan API?

Pelayan API ialah komponen panel kawalan Kubernetes yang mendedahkan API Kubernetes. Pelayan API ialah bahagian klien panel kawalan Kubernetes

Sesiapa sahaja yang pernah melakukan apa-apa dengan Kubernetes terpaksa berinteraksi dengan API sama ada secara langsung atau melalui kubectl. Inilah nadi yang menjadikan Kubernetes Kubernetes - otak yang menjadikan gunung YAML yang kita semua kenal dan suka (?) menjadi infrastruktur yang berfungsi. Nampaknya jelas bahawa API harus hadir dalam konfigurasi minimum kami.

Prasyarat

  • Mesin maya atau fizikal Linux dengan akses root (saya menggunakan Ubuntu 18.04 pada mesin maya).
  • Dan itu sahaja!

Pemasangan yang membosankan

Kami perlu memasang Docker pada mesin yang akan kami gunakan. (Saya tidak akan menerangkan secara terperinci tentang cara Docker dan bekas berfungsi; jika anda berminat, ada artikel yang indah). Mari pasang sahaja dengan apt:

$ sudo apt install docker.io
$ sudo systemctl start docker

Selepas itu, kita perlu mendapatkan binari Kubernetes. Sebenarnya, untuk pelancaran awal "kluster" kami, kami hanya perlukan kubelet, kerana untuk menjalankan komponen pelayan lain yang boleh kita gunakan kubelet. Untuk berinteraksi dengan kluster kami selepas ia berjalan, kami juga akan menggunakan kubectl.

$ curl -L https://dl.k8s.io/v1.18.5/kubernetes-server-linux-amd64.tar.gz > server.tar.gz
$ tar xzvf server.tar.gz
$ cp kubernetes/server/bin/kubelet .
$ cp kubernetes/server/bin/kubectl .
$ ./kubelet --version
Kubernetes v1.18.5

Apa yang berlaku jika kita hanya berlari kubelet?

$ ./kubelet
F0609 04:03:29.105194    4583 server.go:254] mkdir /var/lib/kubelet: permission denied

kubelet mesti dijalankan sebagai root. Agak logik, kerana dia perlu menguruskan keseluruhan nod. Mari lihat parameternya:

$ ./kubelet -h
<слишком ΠΌΠ½ΠΎΠ³ΠΎ строк, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Ρ€Π°Π·ΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ здСсь>
$ ./kubelet -h | wc -l
284

Wah, banyak pilihan! Nasib baik, kami hanya memerlukan beberapa daripada mereka. Berikut ialah salah satu parameter yang kami minati:

--pod-manifest-path string

Laluan ke direktori yang mengandungi fail untuk pod statik, atau laluan ke fail yang menerangkan pod statik. Fail yang bermula dengan titik diabaikan. (DITAMAT: Pilihan ini mesti ditetapkan dalam fail konfigurasi yang dihantar kepada Kubelet melalui pilihan --config. Untuk maklumat lanjut, lihat kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file .)

Pilihan ini membolehkan kita menjalankan pod statik β€” pod yang tidak diurus melalui API Kubernetes. Pod statik jarang digunakan, tetapi ia sangat mudah untuk menaikkan kluster dengan cepat, dan inilah yang kami perlukan. Kami akan mengabaikan amaran besar ini (sekali lagi, jangan jalankan ini dalam pengeluaran!) dan lihat sama ada kami boleh menjalankan pod.

Mula-mula kita akan mencipta direktori untuk pod statik dan jalankan kubelet:

$ mkdir pods
$ sudo ./kubelet --pod-manifest-path=pods

Kemudian, dalam tetingkap terminal/tmux lain/apa sahaja, kami akan mencipta manifes pod:

$ cat <<EOF > pods/hello.yaml
apiVersion: v1
kind: Pod
metadata:
  name: hello
spec:
  containers:
  - image: busybox
    name: hello
    command: ["echo", "hello world!"]
EOF

kubelet mula menulis beberapa amaran dan nampaknya tiada apa yang berlaku. Tetapi itu tidak benar! Mari lihat Docker:

$ sudo docker ps -a
CONTAINER ID        IMAGE                  COMMAND                 CREATED             STATUS                      PORTS               NAMES
8c8a35e26663        busybox                "echo 'hello world!'"   36 seconds ago      Exited (0) 36 seconds ago                       k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4
68f670c3c85f        k8s.gcr.io/pause:3.2   "/pause"                2 minutes ago       Up 2 minutes                                    k8s_POD_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_0
$ sudo docker logs k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4
hello world!

kubelet Saya membaca manifes pod dan memberi Docker arahan untuk melancarkan beberapa bekas mengikut spesifikasi kami. (Jika anda tertanya-tanya tentang bekas "jeda", ia adalah penggodaman Kubernetes - lihat blog ini.) Kubelet akan melancarkan kontena kami busybox dengan arahan yang ditentukan dan akan memulakannya semula selama-lamanya sehingga pod statik dipadamkan.

Tahniah pada diri sendiri. Kami baru sahaja menghasilkan salah satu cara yang paling mengelirukan untuk mengeluarkan teks ke terminal!

Pelancaran dll

Matlamat utama kami adalah untuk menjalankan API Kubernetes, tetapi untuk melakukannya, kami perlu menjalankannya terlebih dahulu dll. Mari kita mulakan kluster etcd minimum dengan meletakkan tetapannya dalam direktori pod (contohnya, pods/etcd.yaml):

apiVersion: v1
kind: Pod
metadata:
  name: etcd
  namespace: kube-system
spec:
  containers:
  - name: etcd
    command:
    - etcd
    - --data-dir=/var/lib/etcd
    image: k8s.gcr.io/etcd:3.4.3-0
    volumeMounts:
    - mountPath: /var/lib/etcd
      name: etcd-data
  hostNetwork: true
  volumes:
  - hostPath:
      path: /var/lib/etcd
      type: DirectoryOrCreate
    name: etcd-data

Jika anda pernah bekerja dengan Kubernetes, fail YAML ini sepatutnya biasa kepada anda. Terdapat hanya dua perkara yang perlu diperhatikan di sini:

Kami telah memasang folder hos /var/lib/etcd dalam pod supaya data etcd dikekalkan selepas dimulakan semula (jika ini tidak dilakukan, keadaan kluster akan dipadamkan setiap kali pod dimulakan semula, yang tidak akan baik untuk pemasangan Kubernetes yang minimum).

Kami telah memasang hostNetwork: true. Tetapan ini, secara tidak menghairankan, mengkonfigurasi etcd untuk menggunakan rangkaian hos dan bukannya rangkaian dalaman pod (ini akan memudahkan pelayan API mencari kluster etcd).

Semakan mudah menunjukkan bahawa etcd memang berjalan pada localhost dan menyimpan data ke cakera:

$ curl localhost:2379/version
{"etcdserver":"3.4.3","etcdcluster":"3.4.0"}
$ sudo tree /var/lib/etcd/
/var/lib/etcd/
└── member
    β”œβ”€β”€ snap
    β”‚   └── db
    └── wal
        β”œβ”€β”€ 0.tmp
        └── 0000000000000000-0000000000000000.wal

Memulakan pelayan API

Menjalankan pelayan API Kubernetes adalah lebih mudah. Satu-satunya parameter yang perlu dilalui ialah --etcd-servers, melakukan apa yang anda harapkan:

apiVersion: v1
kind: Pod
metadata:
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - name: kube-apiserver
    command:
    - kube-apiserver
    - --etcd-servers=http://127.0.0.1:2379
    image: k8s.gcr.io/kube-apiserver:v1.18.5
  hostNetwork: true

Letakkan fail YAML ini dalam direktori pods, dan pelayan API akan bermula. Menyemak dengan curl menunjukkan bahawa API Kubernetes sedang mendengar pada port 8080 dengan akses terbuka sepenuhnya - tiada pengesahan diperlukan!

$ curl localhost:8080/healthz
ok
$ curl localhost:8080/api/v1/pods
{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/pods",
    "resourceVersion": "59"
  },
  "items": []
}

(Sekali lagi, jangan jalankan ini dalam pengeluaran! Saya agak terkejut kerana tetapan lalai sangat tidak selamat. Tetapi saya rasa ini adalah untuk menjadikan pembangunan dan ujian lebih mudah.)

Dan, kejutan yang menyenangkan, kubectl berfungsi di luar kotak tanpa sebarang tetapan tambahan!

$ ./kubectl version
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.5", GitCommit:"e6503f8d8f769ace2f338794c914a96fc335df0f", GitTreeState:"clean", BuildDate:"2020-06-26T03:47:41Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.5", GitCommit:"e6503f8d8f769ace2f338794c914a96fc335df0f", GitTreeState:"clean", BuildDate:"2020-06-26T03:39:24Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
$ ./kubectl get pod
No resources found in default namespace.

masalah

Tetapi jika anda menggali sedikit lebih dalam, ada sesuatu yang tidak kena:

$ ./kubectl get pod -n kube-system
No resources found in kube-system namespace.

Pod statik yang kami buat telah hilang! Malah, nod kubelet kami tidak ditemui sama sekali:

$ ./kubectl get nodes
No resources found in default namespace.

Apa masalahnya? Jika anda masih ingat beberapa perenggan yang lalu, kami memulakan kubelet dengan set parameter baris arahan yang sangat mudah, jadi kubelet tidak tahu cara menghubungi pelayan API dan memberitahu keadaannya. Selepas mengkaji dokumentasi, kami dapati bendera yang sepadan:

--kubeconfig string

Laluan ke fail kubeconfig, yang menentukan cara menyambung ke pelayan API. Ketersediaan --kubeconfig membolehkan mod pelayan API, tidak --kubeconfig membolehkan mod luar talian.

Selama ini, tanpa disedari, kami menjalankan kubelet dalam "mod luar talian." (Jika kita bersikap pedantik, kita boleh menganggap kubelet kendiri sebagai "Kubernetes berdaya maju minimum", tetapi itu akan menjadi sangat membosankan). Untuk membuat konfigurasi "sebenar" berfungsi, kita perlu menghantar fail kubeconfig ke kubelet supaya ia tahu cara bercakap dengan pelayan API. Nasib baik ia agak mudah (kerana kami tidak mempunyai sebarang isu pengesahan atau sijil):

apiVersion: v1
kind: Config
clusters:
- cluster:
    server: http://127.0.0.1:8080
  name: mink8s
contexts:
- context:
    cluster: mink8s
  name: mink8s
current-context: mink8s

Simpan ini sebagai kubeconfig.yaml, membunuh proses kubelet dan mulakan semula dengan parameter yang diperlukan:

$ sudo ./kubelet --pod-manifest-path=pods --kubeconfig=kubeconfig.yaml

(Dengan cara ini, jika anda cuba mengakses API melalui curl apabila kubelet tidak berjalan, anda akan mendapati ia masih berjalan! Kubelet bukan "induk" podnya seperti Docker, ia lebih seperti "kawalan daemon.” Bekas yang diuruskan oleh kubelet akan terus berjalan sehingga kubelet menghalangnya.)

Dalam beberapa minit kubectl harus menunjukkan kepada kita pod dan nod seperti yang kita harapkan:

$ ./kubectl get pods -A
NAMESPACE     NAME                    READY   STATUS             RESTARTS   AGE
default       hello-mink8s            0/1     CrashLoopBackOff   261        21h
kube-system   etcd-mink8s             1/1     Running            0          21h
kube-system   kube-apiserver-mink8s   1/1     Running            0          21h
$ ./kubectl get nodes -owide
NAME     STATUS   ROLES    AGE   VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION       CONTAINER-RUNTIME
mink8s   Ready    <none>   21h   v1.18.5   10.70.10.228   <none>        Ubuntu 18.04.4 LTS   4.15.0-109-generic   docker://19.3.6

Mari kita ucapkan tahniah kepada diri sendiri kali ini (saya tahu saya sudah mengucapkan tahniah kepada diri sendiri) - kita mempunyai "kelompok" Kubernetes yang minimum berjalan dengan API berfungsi sepenuhnya!

Kami melancarkan di bawah

Sekarang mari kita lihat apa yang API mampu. Mari kita mulakan dengan pod nginx:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx

Di sini kita mendapat ralat yang agak menarik:

$ ./kubectl apply -f nginx.yaml
Error from server (Forbidden): error when creating "nginx.yaml": pods "nginx" is
forbidden: error looking up service account default/default: serviceaccount
"default" not found
$ ./kubectl get serviceaccounts
No resources found in default namespace.

Di sini kami melihat betapa tidak lengkapnya persekitaran Kubernetes kami - kami tidak mempunyai akaun untuk perkhidmatan. Mari cuba lagi dengan membuat akaun perkhidmatan secara manual dan lihat apa yang berlaku:

$ cat <<EOS | ./kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
  namespace: default
EOS
serviceaccount/default created
$ ./kubectl apply -f nginx.yaml
Error from server (ServerTimeout): error when creating "nginx.yaml": No API
token found for service account "default", retry after the token is
automatically created and added to the service account

Walaupun kami mencipta akaun perkhidmatan secara manual, token pengesahan tidak dijana. Semasa kami terus mencuba "kluster" minimalis kami, kami akan mendapati bahawa kebanyakan perkara berguna yang biasanya berlaku secara automatik akan hilang. Pelayan API Kubernetes agak minimalis, dengan kebanyakan pengangkatan berat dan konfigurasi automatik berlaku dalam pelbagai pengawal dan kerja latar belakang yang belum dijalankan.

Kita boleh mengatasi masalah ini dengan menetapkan pilihan automountServiceAccountToken untuk akaun perkhidmatan (kerana kami tidak perlu menggunakannya lagi):

$ cat <<EOS | ./kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
  namespace: default
automountServiceAccountToken: false
EOS
serviceaccount/default configured
$ ./kubectl apply -f nginx.yaml
pod/nginx created
$ ./kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   0/1     Pending   0          13m

Akhirnya, pod telah muncul! Tetapi sebenarnya ia tidak akan bermula kerana kita tidak mempunyai perancang (penjadual) ialah satu lagi komponen penting Kubernetes. Sekali lagi, kami melihat bahawa API Kubernetes adalah "bodoh" yang menghairankan - apabila anda mencipta Pod dalam API, ia mendaftarkannya, tetapi tidak cuba memikirkan nod untuk menjalankannya.

Malah, anda tidak memerlukan penjadual untuk menjalankan pod. Anda boleh menambah nod secara manual pada manifes dalam parameter nodeName:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
  nodeName: mink8s

(Ganti mink8s kepada nama nod.) Selepas memadam dan memohon, kami melihat bahawa nginx telah bermula dan sedang mendengar alamat IP dalaman:

$ ./kubectl delete pod nginx
pod "nginx" deleted
$ ./kubectl apply -f nginx.yaml
pod/nginx created
$ ./kubectl get pods -owide
NAME    READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          30s   172.17.0.2   mink8s   <none>           <none>
$ curl -s 172.17.0.2 | head -4
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

Untuk memastikan bahawa rangkaian antara pod berfungsi dengan betul, kita boleh menjalankan curl dari pod lain:

$ cat <<EOS | ./kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: curl
spec:
  containers:
  - image: curlimages/curl
    name: curl
    command: ["curl", "172.17.0.2"]
  nodeName: mink8s
EOS
pod/curl created
$ ./kubectl logs curl | head -6
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

Agak menarik untuk menggali persekitaran ini dan melihat apa yang berkesan dan apa yang tidak. Saya mendapati bahawa ConfigMap dan Rahsia berfungsi seperti yang diharapkan, tetapi Perkhidmatan dan Penggunaan tidak.

Berjaya!

Siaran ini semakin panjang, jadi saya akan mengisytiharkan kemenangan dan mengatakan bahawa ini ialah konfigurasi berdaya maju yang boleh dipanggil "Kubernetes". Untuk meringkaskan: empat binari, lima parameter baris arahan dan "hanya" 45 baris YAML (bukan sebanyak itu mengikut piawaian Kubernetes) dan kami mempunyai beberapa perkara yang berfungsi:

  • Pod diurus menggunakan API Kubernetes biasa (dengan beberapa peretasan)
  • Anda boleh memuat naik dan mengurus imej bekas awam
  • Pod kekal hidup dan dimulakan semula secara automatik
  • Rangkaian antara pod dalam nod yang sama berfungsi dengan baik
  • ConfigMap, Rahsia dan kerja pemasangan storan ringkas seperti yang diharapkan

Tetapi kebanyakan perkara yang menjadikan Kubernetes benar-benar berguna masih tiada, seperti:

  • Penjadual Pod
  • Pengesahan/keizinan
  • Berbilang nod
  • Rangkaian perkhidmatan
  • DNS dalaman berkelompok
  • Pengawal untuk akaun perkhidmatan, penggunaan, penyepaduan dengan penyedia awan dan kebanyakan barangan lain yang Kubernetes bawa

Jadi apa sebenarnya yang kita dapat? API Kubernetes, berjalan sendiri, sebenarnya hanyalah platform untuk automasi kontena. Ia tidak banyak membantu - ia adalah tugas untuk pelbagai pengawal dan pengendali yang menggunakan API - tetapi ia menyediakan persekitaran yang konsisten untuk automasi.

Ketahui lebih lanjut tentang kursus dalam webinar percuma.

Baca lebih lanjut:

Sumber: www.habr.com

Tambah komen