Minimi elinkelpoinen Kubernetes

Artikkelin käännös valmistettiin kurssin alkamisen aattona "DevOps-käytännöt ja -työkalut".

Minimi elinkelpoinen Kubernetes

Jos luet tätä, olet luultavasti kuullut jotain Kubernetesista (ja jos et, kuinka päädyit tänne?) Mutta mikä Kubernetes oikein on? Tämä "Teollisuustason konttien orkestrointi"? Tai "Cloud-Native-käyttöjärjestelmä"? Mitä tämä edes tarkoittaa?

Rehellisesti sanottuna en ole 100% varma. Mutta mielestäni on mielenkiintoista kaivaa sisäisyyteen ja nähdä, mitä Kubernetesissa todella tapahtuu sen monien abstraktiokerrosten alla. Joten huvin vuoksi katsotaanpa miltä pieni "Kubernetes-klusteri" itse asiassa näyttää. (Tämä on paljon helpompaa kuin Kubernetes kova tie.)

Oletan, että sinulla on perustiedot Kubernetesista, Linuxista ja konteista. Kaikki, mistä täällä puhumme, on vain tutkimus-/oppimistarkoituksiin, älä laita sitä tuotantoon!

Arvostelu

Kubernetes sisältää monia komponentteja. Mukaan wikipedia, arkkitehtuuri näyttää tältä:

Minimi elinkelpoinen Kubernetes

Tässä näkyy ainakin kahdeksan komponenttia, mutta jätämme useimmat niistä huomiotta. Haluan todeta, että vähimmäisasia, jota voidaan kohtuudella kutsua Kubernetesiksi, koostuu kolmesta pääkomponentista:

  • kuutio
  • kube-apiserver (joka riippuu etcd:stä - sen tietokannasta)
  • kontin suoritusaika (tässä tapauksessa Docker)

Katsotaanpa mitä dokumentaatio sanoo jokaisesta heistä (venäläinen., Englanti.). Ensiksi kuutio:

Agentti, joka toimii klusterin jokaisessa solmussa. Se varmistaa, että säiliöt kulkevat kotelossa.

Kuulostaa riittävän yksinkertaiselta. Entä kontin ajoajat (säilön käyttöaika)?

Säilön suoritusaika on ohjelma, joka on suunniteltu suorittamaan säiliöitä.

Erittäin informatiivinen. Mutta jos olet perehtynyt Dockeriin, sinulla pitäisi olla yleinen käsitys siitä, mitä se tekee. (Säilön suoritusajan ja kubeletin välisten vastuiden jakamisen yksityiskohdat ovat itse asiassa melko hienovaraisia, enkä käsittele niitä tässä.)

И API-palvelin?

API-palvelin on Kubernetes-ohjauspaneelin komponentti, joka paljastaa Kubernetes API:n. API-palvelin on Kubernetes-ohjauspaneelin asiakaspuoli

Jokainen, joka on koskaan tehnyt mitään Kubernetesin kanssa, on joutunut olemaan vuorovaikutuksessa API:n kanssa joko suoraan tai kubectlin kautta. Tämä on Kubernetes Kubernetesin ydin – aivot, jotka muuttavat YAML-vuoret, jotka me kaikki tunnemme ja rakastamme (?) toimivaksi infrastruktuuriksi. Vaikuttaa ilmeiseltä, että API:n pitäisi olla läsnä minimaalisessa kokoonpanossamme.

Edellytykset

  • Linux-virtuaalinen tai fyysinen kone pääkäyttäjän oikeuksilla (käytän Ubuntu 18.04:ää virtuaalikoneessa).
  • Ja siinä kaikki!

Tylsä asennus

Meidän on asennettava Docker käytettävälle koneelle. (En aio mennä yksityiskohtiin siitä, kuinka Docker ja kontit toimivat; jos olet kiinnostunut, siellä on upeita artikkeleita). Asennamme sen kanssa apt:

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

Sen jälkeen meidän on hankittava Kubernetes-binäärit. Itse asiassa tarvitsemme vain "klusterimme" ensimmäistä käynnistämistä varten kubelet, koska voimme käyttää muita palvelinkomponentteja kubelet. Käytämme myös klusterin kanssa vuorovaikutukseen sen käytön jälkeen 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

Mitä tapahtuu, jos vain juoksemme kubelet?

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

kubelet täytyy suorittaa root-käyttäjänä. Melko loogista, koska hänen täytyy hallita koko solmua. Katsotaanpa sen parametreja:

$ ./kubelet -h
<слишком много строк, чтобы разместить здесь>
$ ./kubelet -h | wc -l
284

Vau, niin monta vaihtoehtoa! Onneksi niitä tarvitaan vain pari. Tässä on yksi meitä kiinnostavista parametreista:

--pod-manifest-path string

Polku hakemistoon, joka sisältää tiedostot staattisia podeja varten, tai polku tiedostoon, joka kuvaa staattisia podeja. Pisteillä alkavat tiedostot ohitetaan. (POISTETTU: Tämä asetus on asetettava asetustiedostossa, joka välitetään Kubeletille --config-valitsimen kautta. Lisätietoja on kohdassa kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file .)

Tämä vaihtoehto antaa meille mahdollisuuden juosta staattiset pussit — podit, joita ei hallita Kubernetes API:n kautta. Staattisia podeja käytetään harvoin, mutta ne ovat erittäin käteviä klusterin nopeaan nostamiseen, ja juuri tätä tarvitsemme. Ohitamme tämän suuren varoituksen (jälleen, älä käytä tätä tuotannossa!) ja katsomme, saammeko podin toimimaan.

Ensin luodaan hakemisto staattisille podille ja suoritetaan kubelet:

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

Sitten toisessa terminaalissa/tmux-ikkunassa/mihin tahansa luomme pod-luettelon:

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

kubelet alkaa kirjoittaa varoituksia ja näyttää siltä, ​​​​että mitään ei tapahdu. Mutta se ei ole totta! Katsotaanpa Dockeria:

$ 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 Luin pod-luettelon ja annoin Dockerille komennon käynnistää pari konttia määritystemme mukaan. (Jos ihmettelet "tauko"-säiliötä, se on Kubernetes-hakkerointi - katso tämä blogi.) Kubelet käynnistää konttimme busybox määritetyllä komennolla ja käynnistää sen uudelleen rajoituksetta, kunnes staattinen pod poistetaan.

Onnittele itseäsi. Keksimme juuri yhden hämmentävämmistä tavoista lähettää tekstiä terminaaliin!

Käynnistä etcd

Lopullinen tavoitteemme on käyttää Kubernetes API:ta, mutta tehdäksemme sen meidän on ensin suoritettava jne. Aloitetaan minimaalinen etcd-klusteri asettamalla sen asetukset pods-hakemistoon (esim. 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

Jos olet koskaan työskennellyt Kubernetesin kanssa, näiden YAML-tiedostojen pitäisi olla sinulle tuttuja. Tässä on vain kaksi huomionarvoista seikkaa:

Olemme asentaneet isäntäkansion /var/lib/etcd podissa niin, että etcd-tiedot säilyvät uudelleenkäynnistyksen jälkeen (jos näin ei tehdä, klusterin tila poistetaan aina, kun pod käynnistetään uudelleen, mikä ei ole hyvä edes minimaaliselle Kubernetes-asennukselle).

Olemme asentaneet hostNetwork: true. Tämä asetus ei ole yllättävää, että etcd määrittää käyttämään isäntäverkkoa podin sisäisen verkon sijaan (tämä helpottaa API-palvelimen löytämistä etcd-klusterin).

Yksinkertainen tarkistus osoittaa, että etcd todellakin toimii localhostissa ja tallentaa tietoja levylle:

$ 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

API-palvelimen käynnistäminen

Kubernetes API -palvelimen käyttäminen on vieläkin helpompaa. Ainoa parametri, joka on välitettävä, on --etcd-servers, tekee mitä odotat:

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

Aseta tämä YAML-tiedosto hakemistoon pods, ja API-palvelin käynnistyy. Tarkistetaan kanssa curl osoittaa, että Kubernetes API kuuntelee porttia 8080 täysin avoimella pääsyllä - todennusta ei vaadita!

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

(Jälleen, älä käytä tätä tuotannossa! Olin hieman yllättynyt, että oletusasetus on niin epävarma. Mutta veikkaan, että tämä helpottaa kehitystä ja testausta.)

Ja iloinen yllätys, kubectl toimii heti ilman lisäasetuksia!

$ ./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.

ongelma

Mutta jos kaivaa hieman syvemmälle, jokin näyttää olevan vialla:

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

Luomamme staattiset kotelot ovat poissa! Itse asiassa kubelet-solmuamme ei löydetä ollenkaan:

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

Mikä hätänä? Jos muistat muutaman kappaleen sitten, aloitimme kubeletin erittäin yksinkertaisella komentoriviparametrijoukolla, joten kubelet ei osaa ottaa yhteyttä API-palvelimeen ja ilmoittaa sille tilastaan. Tutkittuamme dokumentaatiota löydämme vastaavan lipun:

--kubeconfig string

Tiedoston polku kubeconfig, joka määrittää kuinka muodostaa yhteys API-palvelimeen. Saatavuus --kubeconfig ottaa käyttöön API-palvelintilan, ei --kubeconfig ottaa käyttöön offline-tilan.

Koko tämän ajan, tietämättämme, käytimme kubeletia "offline-tilassa". (Jos olisimme pedanttisia, voisimme ajatella erillisen kubeletin "vähintään elinkelpoisena Kubernetesina", mutta se olisi erittäin tylsää). Jotta "oikea" määritys toimisi, meidän on välitettävä kubeconfig-tiedosto kubeletille, jotta se osaa puhua API-palvelimen kanssa. Onneksi se on melko yksinkertainen (koska meillä ei ole todennus- tai varmenneongelmia):

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

Tallenna tämä nimellä kubeconfig.yaml, lopeta prosessi kubelet ja käynnistä uudelleen tarvittavilla parametreilla:

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

(Muuten, jos yrität päästä API:aan curlin kautta, kun kubelet ei ole käynnissä, huomaat, että se on edelleen käynnissä! Kubelet ei ole podistiensa "vanhempi" kuten Docker, se on enemmän kuin "hallinta" daemon." Kubeletin hallitsemat säilöt jatkavat toimintaansa, kunnes kubelet pysäyttää ne.)

Muutamassa minuutissa kubectl pitäisi näyttää meille podit ja solmut odotetulla tavalla:

$ ./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

Onnittelemme todella itseämme tällä kertaa (tiedän, että onnittelin jo itseämme) - meillä on minimaalinen Kubernetes "klusteri" täysin toimivalla API:lla!

Aloitamme alta

Katsotaan nyt, mihin API pystyy. Aloitetaan nginx podista:

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

Tässä saamme melko mielenkiintoisen virheen:

$ ./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.

Tässä näemme, kuinka surkeasti epätäydellinen Kubernetes-ympäristömme on - meillä ei ole palveluita. Yritetään uudelleen luomalla palvelutili manuaalisesti ja katsotaan mitä tapahtuu:

$ 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

Vaikka loimme palvelutilin manuaalisesti, todennustunnusta ei luoda. Jatkaessamme minimalistisen "klusterin" kokeilua huomaamme, että suurin osa hyödyllisistä asioista, jotka yleensä tapahtuvat automaattisesti, puuttuvat. Kubernetes API-palvelin on melko minimalistinen, ja suurin osa raskaiden nostoista ja automaattisista määrityksistä tapahtuu erilaisissa ohjaimissa ja taustatöissä, jotka eivät vielä ole käynnissä.

Voimme kiertää tämän ongelman asettamalla vaihtoehdon automountServiceAccountToken palvelutilille (koska meidän ei tarvitse käyttää sitä joka tapauksessa):

$ 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

Vihdoinkin koukku on ilmestynyt! Mutta itse asiassa se ei ala, koska meillä ei ole suunnittelija (scheduler) on toinen tärkeä Kubernetesin osa. Näemme jälleen, että Kubernetes API on yllättävän "tyhmä" - kun luot sovellusliittymään Podin, se rekisteröi sen, mutta ei yritä selvittää, missä solmussa se ajaa.

Itse asiassa et tarvitse ajastinta podin suorittamiseen. Voit lisätä parametrin luetteloon solmun manuaalisesti nodeName:

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

(Korvata mink8s solmun nimeen.) Poistamisen ja käytön jälkeen näemme, että nginx on käynnistynyt ja kuuntelee sisäistä IP-osoitetta:

$ ./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>

Varmistaaksemme, että podien välinen verkko toimii oikein, voimme suorittaa curlin toisesta podista:

$ 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>

On mielenkiintoista kaivaa tähän ympäristöön ja nähdä, mikä toimii ja mikä ei. Huomasin, että ConfigMap ja Secret toimivat odotetusti, mutta Service ja Deployment eivät.

Selvä!

Tästä viestistä tulee pitkä, joten julistan voiton ja sanon, että tämä on käyttökelpoinen kokoonpano, jota voidaan kutsua "Kubernetesiksi". Yhteenvetona: neljä binaaritiedostoa, viisi komentoriviparametria ja "vain" 45 riviä YAML:a (ei niin paljon standardien mukaan Kubernetes) ja meillä on melko vähän toimivia asioita:

  • Podeja hallitaan tavallisella Kubernetes API:lla (muutamalla hakkeroinnilla)
  • Voit ladata ja hallita julkisia säilökuvia
  • Podit pysyvät elossa ja käynnistyvät automaattisesti uudelleen
  • Verkostoituminen podien välillä saman solmun sisällä toimii melko hyvin
  • ConfigMap, Secret ja yksinkertainen tallennustilan asennus toimivat odotetusti

Mutta paljon siitä, mikä tekee Kubernetesista todella hyödyllisen, puuttuu edelleen, kuten:

  • Pod-aikataulu
  • Todennus/valtuutus
  • Useita solmuja
  • Palveluverkosto
  • Klusteroitu sisäinen DNS
  • Ohjaimet palvelutileille, käyttöönottoille, integraatiolle pilvipalveluntarjoajien kanssa ja useimpiin muihin Kubernetesin tuomiin herkkuihin

Mitä me siis oikeastaan ​​saimme? Kubernetes API, joka toimii yksinään, on oikeastaan ​​vain alusta konttiautomaatio. Se ei tee paljoa – se on työskentely useille APIa käyttäville ohjaajille ja operaattoreille – mutta se tarjoaa johdonmukaisen ympäristön automaatiota varten.

Lue lisää kurssista ilmaisessa webinaarissa.

Lue lisää:

Lähde: will.com

Lisää kommentti