Продолжительность занятия:
Предварительные требования
Эволюция технологий разработки
Для решения каких проблем развивались виртуализация и контейнерные технологии? Изоляция ресурсов & ограничение ресурсов
Что такое Linux-контейнеры? namespace & cgroup
Что такое lxc namespace?
Что такое CGroup?
Есть ли контейнерные технологии для Mac и Win?
Что такое Docker ( Быстрый старт )?
- Каковы отношения между Docker и контейнерами (почему Линус не заботится о Docker)?
Какие конкурентные продукты у Docker? CRI-O ?, другие командные инструменты для контейнеров: GitHub или Gitee### 1.4 Какова архитектура и пространство понятий Docker?
Пространство понятий
Модульная архитектура
Природная неуязвимость и природная уязвимость контейнеров
Конкуренты: gVisor / firecracker / rustVM
На CentOS 7
# Удаление старых версий Docker
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
yum install -y yum-utils
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Установить для запуска при старте системы и запустить сразу
systemctl enable docker --now
# запустить hello-world
docker run hello-world
Как создать образ? Как запустить и отладить контейнер? Github или Gitee
$ mkdir ~/test
$ cd ~/test
$ wget https://gitee.com/dev-99cloud/lab-openstack/raw/master/src/docker-quickstart/app.py
$ wget https://gitee.com/dev-99cloud/lab-openstack/raw/master/src/docker-quickstart/requirements.txt
$ wget https://gitee.com/dev-99cloud/lab-openstack/raw/master/src/docker-quickstart/Dockerfile
``` # Если используется CentOS 7.x, нужно установить python3
$ yum install python3 python3-pip
# pip3 install -r requirements.txt
$ pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
$ python3 app.py
* Запущено на http://0.0.0.0:80/ (Нажмите CTRL+C для остановки)
# В это время можно получить доступ к http://<ip>/ через браузер
$ docker build --tag=friendlyhello .
# Можно посмотреть локальный список образов
$ docker images
# Удалить существующий контейнер testFlask
$ docker rm testFlask 2>/dev/null
# Запустить контейнер testFlask с образом 99cloud/friendlyhello:3.9.6, порт 80 контейнера отображается на порт 4000 хоста
# Если использовать --rm параметр, контейнер будет удален после остановки
$ docker run -p 4000:80 --name=testFlask 99cloud/friendlyhello:3.9.6
* Запущено на http://0.0.0.0:80/ (Нажмите CTRL+C для остановки)
# В это время можно получить доступ к http://<ip>:4000 через браузер
# Если нужно запустить в фоновом режиме, можно использовать -d параметр
$ docker run -d -p 4000:80 --name=testFlask 99cloud/friendlyhello:3.9.6
# Войти в контейнер для отладки
$ docker exec -it testFlask /bin/bash
root@4224b69e7ee3:/app# env
HOSTNAME=4224b69e7ee3
PWD=/app
HOME=/root
NAME=World
...
root@4224b69e7ee3:/app# ps -ef
# Просмотреть логи контейнера
$ docker logs -f testFlask
``` # Остановить контейнер
$ docker stop testFlask
# Запустить контейнер
$ docker start testFlask
# Создать новый образ из контейнера
$ docker stop testFlask
$ docker commit testFlask test-new
# Удалить контейнер
$ docker rm testFlask # Удалить образ
$ docker rmi friendlyhello
$ docker rmi 99cloud/friendlyhello:3.9.6
На Ubuntu 18.04 / Ubuntu 20.04
# Обновить репозитории
apt-get update -y || yum update -y
# Установить Docker
apt-get install docker.io -y || yum install docker -y
systemctl enable docker
systemctl start docker
# Проверить статус службы docker
systemctl status docker
# На Ubuntu необходимо изменить cgroup driver Docker на systemd
# !! На CentOS старые версии Docker 1.13 по умолчанию используют systemd, не изменяйте этот файл, новый Docker 24+ требует изменения
vi /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
systemctl restart docker
# Запустить hello-world
docker run hello-world
``` >Примечание: С июля 2021 года в окружении Ubuntu kubeadmin по умолчанию версии 1.22+, поэтому необходимо изменить cgroup driver Docker на systemd (ранее использовался cgroup). В противном случае, при выполнении kubeadm init будет ошибка: `[kubelet-check] HTTP-запрос, равный 'curl -sSL http://localhost:10248/healthz' вернул ошибку: Get "http://localhost:10248/healthz": dial tcp [::1]:10248: connect: connection refused.`
>
>Проверьте journalctl -x -u kubelet, чтобы увидеть: `Aug 07 15:10:45 ckalab2 kubelet[11394]: E0807 15:10:45.179485 11394 server.go:294] "Failed to run kubelet" err="failed to run Kubelet: misconfiguration: kubelet cgroup driver: \"systemd\" is different from docker cgroup driver: \"cgroupfs\""`
>
>См. официальную документацию: <https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/>: `В версии v1.22, если пользователь не устанавливает поле cgroupDriver под KubeletConfiguration, kubeadm по умолчанию установит его в systemd.`
>
>Поэтому нам необходимо изменить cgroup driver Docker на systemd.
>
>Шаги изменения см. в: <https://stackoverflow.com/questions/43794169/docker-change-cgroup-driver-to-systemd>
>
>После завершения изменений, проверьте cgroup Docker, чтобы убедиться, что cgroup Docker теперь systemd: `sudo docker info | grep -i cgroup`- [Официальная документация Docker для начинающих](https://docs.docker.com/get-started/)### 1.7 Сетевая модель Docker
Режим Bridge
# Docker-контейнеры не помещают network namespaces в стандартное место `/var/run/netns`, поэтому команда `ip netns list` ничего не покажет
# Однако можно проверить `ll /proc/<pid>/ns`, если идентификаторы пространств имен двух процессов совпадают, значит они находятся в одном пространстве имен
[root@cloud025 ns]# ll /proc/2179/ns/
total 0
lrwxrwxrwx 1 root root 0 Aug 10 11:58 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Aug 10 11:58 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Aug 10 11:58 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0 Aug 10 11:58 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Aug 10 11:58 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Aug 10 11:58 uts -> uts:[4026531838]
# Создание символической ссылки позволяет увидеть netns
[root@cloud025 ns]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
07297a3ac7ea nginx:latest "/docker-entrypoin..." 29 минут назад Up 29 минут 80/tcp devtest
0935b08509a4 test-new "python app.py" 35 минут назад Up 35 минут 0.0.0.0:5000->80/tcp testNew
c23c76dd779c 99cloud/friendlyhello:3.9.6 "python app.py" 37 минут назад Up 36 минут 0.0.0.0:4000->80/tcp testFlask
[root@cloud025 ns]# docker inspect testFlask | grep -i pid
"Pid": 1159,
"PidMode": "",
"PidsLimit": 0,
[root@cloud025 ns]# mkdir -p /var/run/netns
[root@cloud025 ns]# ln -s /proc/1159/ns/net /var/run/netns/testFlask
[root@cloud025 ns]# ip netns list
testFlask (id: 0)
devtest (id: 2)
testNew (id: 1)
``` # Вход в соответствующее пространство имен и просмотр ip, виртуальная сетевая карта в пространстве имен pod имеет link-netnsid равный 0
[root@cloud025 ns]# ip netns exec testNew ip a
...
44: eth0@if45: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.3/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:3/64 scope link
valid_lft forever preferred_lft forever
[root@cloud025 ns]# ip a 45: vethb6d08be@if44: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 0e:d9:14:d1:86:98 brd ff:ff:ff:ff:ff:ff link-netnsid 1 inet6 fe80::cd9:14ff:fed1:8698/64 scope link valid_lft forever preferred_lft forever # Это пара veth, их можно определить по номерам и if
[root@cloud025 ~]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.02428c25c112 no vethb6d08be virbr0 8000.525400d583b9 yes virbr0-nic
[Можно попробовать перехватить трафик виртуальной сетевой карты, чтобы отслеживать входящий и исходящий трафик контейнеров](#81-мониторинг-логов-и-исправление-ошибок)
Host-режим
CNM
[root@cka-studenta-1 ~]# mkdir testhaha
[root@cka-studenta-1 ~]# docker run -d -it --name devtest -v "$(pwd)"/testhaha:/app nginx:latest
Не удалось найти изображение 'nginx:latest' локально
Попытка загрузки репозитория docker.io/library/nginx ...
latest: Загрузка из docker.io/library/nginx ...
...
7897813b7065a0390db335656443782895155655f263de6ee8264a6f2185fe16
[root@cka-studenta-1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7897813b7065 nginx:latest "/docker-entrypoin..." 6 seconds ago Up 4 seconds 80/tcp devtest
b667b8e2f90b 99cloud/friendlyhello:3.9.6 "python app.py" 3 hours ago Up 3 hours 0.0.0.0:4000->80/tcp testFlask
[root@cka-studenta-1 ~]# docker exec -it 7897813b7065 /bin/sh
# ls
app bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
# cd app
# ls
# echo fsdfasfdasdfsa > xxxxxxxx.txt
# exit
[root@cka-studenta-1 ~]# ls
test testhaha
[root@cka-studenta-1 ~]# cd testhaha/
[root@cka-studenta-1 testhaha]# ls
xxxxxxxx.txt
[root@cka-studenta-1 testhaha]# cat xxxxxxxx.txt
fsdfasfdasdfsa
Volumn模式
Volumn模式 → Вolume режим## Урок 02: Концепции Kubernetes
Что такое Kubernetes? Это инструмент для управления контейнерами. Почему его называют K8S?
Как K8S связан с Docker? См.: Container runtimes
Orchestration API -> Container API (cri-runtime) -> Kernel API (oci-runtime)
OCI: runC / Kata (и его предшественники runV и Clear Containers), gVisor, Rust railcar
CRI: Docker (с использованием dockershim), containerd (с использованием CRI-containerd), CRI-O, Frakti. Это набор gRPC интерфейсов, cri-api/pkg/apis/services.go:
Обычный вызов K8S Docker
containerd-1.0, адаптация CRI через отдельный процесс CRI-containerd
containerd-1.1, адаптация CRI как плагин, встроенный в основной процесс containerd
CRI-O, более специализированный CRI-режим, чистый и совместимый с CRI и OCI, специализированный для Kubernetes
Как K8S связан с Borg? Начинался с Borg, но полностью отличается!
Какие компоненты есть в K8S? api-server, kube-scheduler, kube-controller, etcd, coredns, kubelet, kubeproxy
Общая структура
Какие преимущества имеет OpenShift (самый ценный продукт Red Hat) по сравнению с K8S?
VMware
KubeSphere
Rancher
# 1. Отключение огнестрельного экрана (по умолчанию отключено в CentOS 7.9 образе на Aliyun, поэтому не требуется)
systemctl stop firewalld.service
systemctl disable firewalld.service
# 2. Отключение SELinux (по умолчанию отключено в CentOS 7.9 образе на Aliyun, поэтому не требуется)
# Изменение SELINUX=enforcing на SELINUX=disabled
vi /etc/selinux/config
# Немедленное отключение SELinux
setenforce 0
# 3. Отключение swap (по умолчанию отключено в CentOS 7.9 образе на Aliyun, поэтому не требуется)
# Комментирование строки swapoff xxx, чтобы избежать включения swap при перезагрузке
vi /etc/fstab
# Немедленное отключение swap
swapoff -a
# 4. Включение параметров ядра
# Постоянное активирование модуля ядра br_netfilter
echo br_netfilter | tee -a /etc/modules
modprobe br_netfilter
# Включение ipv4 forward
cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
# Запуск конфигурации параметров ядра
sysctl -p
sysctl --system
# 5. Настройка репозитория Kubernetes, здесь мы используем репозиторий Aliyun
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
```# 6. [опционально] Удаление предыдущего установленного Docker (возможно, старой версии)
yum remove -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
```# 7. Установка новой версии docker
```bash
yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y
systemctl enable containerd --now
systemctl enable docker --now
containerd config default > /etc/containerd/config.toml
vi /etc/containerd/config.toml
# Обновление sandbox-образа
# sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.6" замените на внутренний репозиторий
# Обновление SystemdCgroup, false замените на true
# SystemdCgroup = true
vi /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
systemctl restart containerd
systemctl restart docker
export k8s_version="1.23.3"
# Установка репозитория для версии 1.23.3
yum install -y kubelet-${k8s_version}-0 kubeadm-${k8s_version}-0 kubectl-${k8s_version}-0 --disableexcludes=kubernetes
systemctl restart kubelet
systemctl enable kubelet
kubeadm config images pull --kubernetes-version ${k8s_version} --image-repository registry.aliyuncs.com/google_containers
kubeadm init --image-repository registry.aliyuncs.com/google_containers --kubernetes-version=v${k8s_version} --pod-network-cidr=10.244.0.0/16
mkdir $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl apply -f https://gitee.com/dev-99cloud/lab-openstack/raw/master/src/ansible-cloudlab-centos/playbooks/roles/init04-prek8s/files/calico-${k8s_version}.yml
```Данный сценарий позволяет K8S работать с Docker. Если требуется использовать containerd напрямую, команда `kubeadm init` должна быть изменена на:
```bash
kubeadm init --cri-socket unix:///run/containerd/containerd.sock --image-repository registry.aliyuncs.com/google_containers --kubernetes-version=v${k8s_version} --pod-network-cidr=10.244.0.0/16
Для получения дополнительной информации см. Github или Gitee. Если требуется переустановка, можно выполнить kubeadm reset -f
Проверка состояния кластера
# Проверка состояния узлов
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
cka-node1 Ready control-plane,master,worker 30s v1.23.3
Установка/добавление GPU-узла в кластер (только если CRI — Docker)
# 1. Установка драйвера для графического адаптера на узле
# См. https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#abstract
# 2. Установка Docker
# См. выше
# 3. Установка nvidia-docker
distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \ && curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.repo | sudo tee /etc/yum.repos.d/nvidia-docker.repo
yum install -y nvidia-docker2
# См. документацию по установке на Ubuntu и других системах https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#installing-on-centos-7-8
``` # 4. Изменение по умолчанию контейнерного runtime
# Редактирование файла `/etc/docker/daemon.json`, добавление следующих полей:
{
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "nvidia-container-runtime",
"runtimeArgs": []
}
}
}
systemctl daemon-reload && systemctl restart docker # 5. Установка кластера Kubernetes или добавление узла в кластер
# 6. Установка плагина vGPU
# * Официальный плагин от Nvidia поддерживает только целый графический адаптер, что не подходит для нашего сценария
# * Плагин gpushare от Alibaba Cloud поддерживает частичное использование GPU, но не обеспечивает изоляцию памяти
# * Плагин vGPU от 4Paradigm поддерживает разбиение графического адаптера и изоляцию памяти
# Установка плагина vGPU от 4Paradigm см. `https://github.com/4paradigm/k8s-device-plugin/blob/master/README_cn.md#Kubernetes%E5%BC%80%E5%90%AFvGPU%E6%94%AF%E6%8C%81`
# Включение прослушивания bridged трафика
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system
apt-get update && apt-get install -y apt-transport-https curl curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main EOF apt-get update -y && apt-get install -y kubelet kubeadm kubectl
systemctl daemon-reload systemctl restart kubelet
systemctl status kubelet
Создание k8s кластера с помощью kubeadm
# Запуск k8s кластера
kubeadm init --pod-network-cidr 192.168.1.90/16
``` # Настройка kubectl клиента
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
В данный момент можно заметить, что узлы не готовы, что приводит к невозможности распределения coredns. Далее необходимо: установка сетевого плагина, список плагинов, здесь мы будем использовать Calico.
# Добавление сетевого плагина
# Установка оператора Tigera Calico и пользовательских ресурсов
kubectl create -f https://docs.projectcalico.org/manifests/tigera-operator.yaml
# Установка Calico путем создания необходимых пользовательских ресурсов
kubectl create -f https://docs.projectcalico.org/manifests/custom-resources.yaml
# Просмотр состояния pods и узлов
kubectl get pods --all-namespaces
kubectl get nodes
[root@cloud025 ~]# ll /proc/10893/ns/
total 0
lrwxrwxrwx 1 root root 0 10 авг 15:33 ipc -> ipc:[4026532513]
lrwxrwxrwx 1 root root 0 10 авг 15:33 mnt -> mnt:[4026532511]
lrwxrwxrwx 1 root root 0 10 авг 15:33 net -> net:[4026532516]
lrwxrwxrwx 1 root root 0 10 авг 16:15 pid -> pid:[4026532514]
lrwxrwxrwx 1 root root 0 10 авг 16:15 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 10 авг 16:15 uts -> uts:[4026532512]
```- Почему основной единицей планирования является pod, а не контейнер?
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
Запуск pod
# Запуск pod nginx
kubectl apply -f nginx.yaml
# Просмотр информации о pod
kubectl describe pod nginx
# Удаление маркера, чтобы pod мог быть запланирован на master
kubectl taint nodes $(hostname) node-role.kubernetes.io/master:NoSchedule-
# Просмотр запланированных pod
kubectl get pods
# Просмотр запущенных контейнеров
docker ps | grep nginx
Развертывание Python-приложения на платформе контейнеризации
Файл requirements.txt
содержит только одну строку: flask, это файл с зависимостями
Файл main.py
содержит логику приложения ```python
from flask import Flask
import os
import socket
app = Flask(name)
@app.route("/") def hello(): html = "
mkdir ~/test-hello-world
cd ~/test-hello-world/
wget https://gitee.com/dev-99cloud/training-kubernetes/raw/master/src/hello-python/main.py
wget https://gitee.com/dev-99cloud/training-kubernetes/raw/master/src/hello-python/requirements.txt
wget https://gitee.com/dev-99cloud/training-kubernetes/raw/master/src/hello-python/Dockerfile
wget https://gitee.com/dev-99cloud/training-kubernetes/raw/master/src/hello-python/deployment.yaml
Локальное выполнение:
pip3 install -r requirements.txt
python3 main.py
, что запускает локальный веб-сервер для разработки.http://<IP>:5000
.Docker-файл для построения образа, в директории находится файл Dockerfile
FROM python:3.7
RUN mkdir /app
WORKDIR /app
ADD . /app/
RUN pip install -r requirements.txt
EXPOSE 5000
CMD ["python", "/app/main.py"]
```- Построение Docker-образа и его запуск
- Команда для построения образа: `docker build -f Dockerfile -t hello-python:latest .`
- После построения образа, вы можете увидеть его с помощью команды `docker image ls`.
- Запустите образ: `docker run -p 5001:5000 hello-python`.
- Перейдите по адресу `http://<IP>:5001`, чтобы увидеть строку `Hello from Python!`.
Убедиться, что Kubernetes и kubectl работают корректно
kubectl version
, если команда выполнена без ошибок, значит kubectl установлен.kubectl get nodes
, если возвращаются данные о узлах, значит K8S работает корректно, а kubectl настроен правильно.Файл YAML для развертывания в Kubernetes: ```yaml apiVersion: v1 kind: Service metadata: name: hello-python-service spec: type: NodePort selector: app: hello-python ports: - protocol: "TCP" port: 6000 targetPort: 5000 nodePort: 31000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-python
spec:
selector:
matchLabels:
app: hello-python
replicas: 4
template:
metadata:
labels:
app: hello-python
spec:
containers:
- name: hello-python
image: hello-python:latest
imagePullPolicy: Never
ports:
- containerPort: 5000
Разверните Deployment на K8S платформе
Выполните команду: kubectl apply -f deployment.yaml
Выполните команду: kubectl get pods, проверьте pods
Затем открыть браузер и перейти по адресу http://<IP>:31000
, чтобы увидеть сообщение Hello from Python!
Эксперимент
# Обратите внимание на связь service / deployment и pod, используя метки
kubectl get pods -l app=hello-python
kubectl get deploy
kubectl get deployment
kubectl get svc
kubectl get service
kubectl get pods -l app=hello-python -o wide
# Доступ к приложению
curl http://<pod-ip>:5000
curl http://<cluster-ip>:6000
curl http://<host-ip>:31000
Namespace & изоляция арендаторов
Эксперимент: namespace & quota
# Создайте namespace
kubectl create namespace quota-mem-cpu-example
``` # Ограничьте ресурсы для этого namespace
kubectl apply -f https://k8s.io/examples/admin/resource/quota-mem-cpu.yaml --namespace=quota-mem-cpu-example
# Просмотрите детали ограничений
kubectl get resourcequota mem-cpu-demo --namespace=quota-mem-cpu-example --output=yaml
# Создайте pod и ограничьте его использование ресурсов
kubectl apply -f https://k8s.io/examples/admin/resource/quota-mem-cpu-pod.yaml --namespace=quota-mem-cpu-example
# Убедитесь, что pod запущен
kubectl get pod quota-mem-cpu-demo --namespace=quota-mem-cpu-example
# Просмотрите детали ограничений, проверьте использованные ресурсы
kubectl get resourcequota mem-cpu-demo --namespace=quota-mem-cpu-example --output=yaml
# Попытайтесь запустить второй pod, из-за ограничений запуск не удался
kubectl apply -f https://k8s.io/examples/admin/resource/quota-mem-cpu-pod-2.yaml --namespace=quota-mem-cpu-example
# Ошибка от сервера (Запрещено): ошибка при создании "examples/admin/resource/quota-mem-cpu-pod-2.yaml": pods "quota-mem-cpu-demo-2" запрещен: превышен лимит: mem-cpu-demo, запрошен: requests.memory=700Mi, использовано: requests.memory=600Mi, ограничен: requests.memory=1Gi
kubectl delete namespace quota-mem-cpu-example
Эксперимент: Pod Label и Replica Controller
kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
kubectl get pods
kubectl get deployments
kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1 --record
kubectl get pods
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.161 --record=true
kubectl get pods
``` kubectl rollout history deployment.v1.apps/nginx-deployment
kubectl rollout history deployment.v1.apps/nginx-deployment --revision=2
kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision=2
kubectl get pods
# Если оригинальный pod с ошибкой ErrorImagePull продолжает неудачно запускаться, можно удалить его командой kubectl delete pod <pod-name> kubectl scale deployment.v1.apps/nginx-deployment --replicas=10
kubectl get pods
Основные понятия: Service
Эксперимент: Service
Создайте файл service.yaml с содержимым:
apiVersion: v1
kind: Service
metadata:
name: hello-python-service
spec:
type: NodePort
selector:
app: nginx
ports:
- protocol: "TCP"
port: 6000
targetPort: 80
nodePort: 31000
kubectl apply -f service.yaml
# После создания сервиса можно посмотреть iptables
$ iptables -t nat -n -L -v
# Вы увидите следующее, запросы на сервис IP распределяются между pod'ами
Chain KUBE-SVC-C5I534CP62HG2LN3 (2 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SEP-FBKE4RDEE4U4O7NI all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/hello-python-service */ statistic mode random probability 0.50000000000
0 0 KUBE-SEP-ZIK7TOCY5OVWTBMA all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/hello-python-service */
kubectl get pods -o wide
kubectl run curl --image=radial/busyboxplus:curl -i --tty
nslookup hello-python-service curl http://hello-python-service.default.svc.cluster.local:6000
nslookup hello-python-service.default.svc.cluster.local 10.96.0.10
LB типа Service: metallb
```yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
terminationGracePeriodSeconds: 30
```
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: statefulset
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: statefulset
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: statefulset # должно совпадать с .spec.template.metadata.labels
serviceName: "nginx"
replicas: 3 # по умолчанию равно 1
template:
metadata:
labels:
app: statefulset # должно совпадать с .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
kubectl apply -f test-statefulset.yaml
kubectl get pods
# headless сервис, у которого нет IP-адреса сервиса
kubectl run curl --image=radial/busyboxplus:curl -i --tty
nslookup nginx
# выполните команду nslookup nginx несколько раз, чтобы увидеть, что порядок возврата каждый раз разный
# headless сервис использует изменение порядка возврата DNS для реализации балансировки нагрузки
```### 3.8 Эксперимент: Операции с ETCD
Установка и получение
# Установка etcd-client в Ubuntu с помощью apt-get
root@ckalab001:~# apt install etcd-client
# В других окружениях можно скачать двоичный файл с https://github.com/etcd-io/etcd/releases
root@ckalab001:~# ps -ef | grep api | grep -i etcd
root 24761 24743 3 10:17 ? 00:06:53 kube-apiserver --advertise-address=172.31.43.206 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/etc/kubernetes/pki/ca.crt --enable-admission-plugins=NodeRestriction --enable-bootstrap-token-auth=true --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --insecure-port=0 --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=6443 --service-account-issuer=https://kubernetes.default.svc.cluster.local --service-account-key-file=/etc/kubernetes/pki/sa.pub --service-account-signing-key-file=/etc/kubernetes/pki/sa.key --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/etc/kubernetes/pki/apiserver.crt --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
# Установка переменной окружения ETCDCTL_API=3
root@ckalab001:~# export ETCDCTL_API=3
``` root@ckalab001:~# etcdctl --cert="/etc/kubernetes/pki/apiserver-etcd-client.crt" --key="/etc/kubernetes/pki/apiserver-etcd-client.key" --cacert="/etc/kubernetes/pki/etcd/ca.crt" --endpoints=https://127.0.0.1:2379 put /firstkey trystack
OK
``` root@ckalab001:~# etcdctl --cert="/etc/kubernetes/pki/apiserver-etcd-client.crt" --key="/etc/kubernetes/pki/apiserver-etcd-client.key" --cacert="/etc/kubernetes/pki/etcd/ca.crt" --endpoints=https://127.0.0.1:2379 get /firstkey
/firstkey
trystack
``` ```bash
# список всех ключей
etcdctl --cert="/etc/kubernetes/pki/apiserver-etcd-client.crt" --key="/etc/kubernetes/pki/apiserver-etcd-client.key" --cacert="/etc/kubernetes/pki/etcd/ca.crt" --endpoints=https://127.0.0.1:2379 get --prefix --keys-only ""
# список всех ключей и значений
etcdctl --cert="/etc/kubernetes/pki/apiserver-etcd-client.crt" --key="/etc/kubernetes/pki/apiserver-etcd-client.key" --cacert="/etc/kubernetes/pki/etcd/ca.crt" --endpoints=https://127.0.0.1:2379 get --prefix ""
# резервное копирование и восстановление
etcdctl --cert="/etc/kubernetes/pki/apiserver-etcd-client.crt" --key="/etc/kubernetes/pki/apiserver-etcd-client.key" --cacert="/etc/kubernetes/pki/etcd/ca.crt" snapshot save a.txt
# шаги восстановления резервной копии
# 1. остановить службу ETCD
# 2. удалить каталог данных ETCD
# 3. восстановить снимок
# 4. перезапустить службу ETCD
etcdctl --cert="/etc/kubernetes/pki/apiserver-etcd-client.crt" --key="/etc/kubernetes/pki/apiserver-etcd-client.key" --cacert="/etc/kubernetes/pki/etcd/ca.crt" snapshot restore a.txt
Эксперимент по резервному копированию и восстановлению:
[root@ckalab003 ~]# etcdctl --cert="/etc/kubernetes/pki/apiserver-etcd-client.crt" --key="/etc/kubernetes/pki/apiserver-etcd-client.key" --cacert="/etc/kubernetes/pki/etcd/ca.crt" put /firstkey-1 test1
OK
[root@ckalab003 ~]# etcdctl --cert="/etc/kubernetes/pki/apiserver-etcd-client.crt" --key="/etc/kubernetes/pki/apiserver-etcd-client.key" --cacert="/etc/kubernetes/pki/etcd/ca.crt" get /firstkey-1
/firstkey-1
test1
[root@ckalab003 ~]# etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key snapshot save backup1
...
Snapshot saved at backup1
``` [root@ckalab003 ~]# etcdctl --cert="/etc/kubernetes/pki/apiserver-etcd-client.crt" --key="/etc/kubernetes/pki/apiserver-etcd-client.key" --cacert="/etc/kubernetes/pki/etcd/ca.crt" put /firstkey-2 test2
OK
[root@ckalab003 ~]# etcdctl --cert="/etc/kubernetes/pki/apiserver-etcd-client.crt" --key="/etc/kubernetes/pki/apiserver-etcd-client.key" --cacert="/etc/kubernetes/pki/etcd/ca.crt" get /firstkey-2 /firstkey-2 test2 [root@ckalab003 ~]# mv /etc/kubernetes/manifests/etcd.yaml . [root@ckalab003 ~]# rm -rf /var/lib/etcd/* [root@ckalab003 ~]# etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key snapshot restore backup1 --data-dir /var/lib/etcd ... 2023-06-17T17:35:25+08:00 info snapshot/v3_snapshot.go:272 restored snapshot {"path": "backup1", "wal-dir": "/var/lib/etcd/member/wal", "data-dir": "/var/lib/etcd", "snap-dir": "/var/lib/etcd/member/snap"}
[root@ckalab003 ~]# mv ./etcd.yaml /etc/kubernetes/manifests/
[root@ckalab003 ~]# etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key get /firstkey-1 /firstkey-1 test1 [root@ckalab003 ~]# etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key get /firstkey-2
`/firstkey-1` виден, а `/firstkey-2` не виден, что соответствует ожиданиям.
Восстановление кластера:
```bash
etcdctl --name ckalab001 --initial-cluster ckalab001=https://139.224.191.4:2380 --initial-cluster-token etcd-cluster --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key --cacert=/etc/kubernetes/pki/etcd/ca.crt --initial-advertise-peer-urls https://139.224.191.4:2380 snapshot restore /root/backup-1 --data-dir /var/lib/etcd
/etc/kubernetes/manifests
root@CKA003:~# ps -ef | grep kubelet
root 10572 1 2 09:37 ? 00:07:41 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --cgroup-driver=cgroupfs --network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2 --resolv-conf=/run/systemd/resolve/resolv.conf
В Kubernetes (K8S) термин "3A" относится к трем основным аспектам аутентификации и авторизации:
Аутентификация: Процесс идентификации пользователя или сущности, которая пытается получить доступ к системе. В K8S это может быть выполнено с помощью различных методов, таких как токены, сертификаты X.509, OAuth и другие.
Авторизация: Процесс проверки прав доступа пользователя или сущности после успешной аутентификации. В K8S это обычно реализуется с помощью объектов Role и RoleBinding или ClusterRole и ClusterRoleBinding.
Управление доступом: Процесс контроля доступа к ресурсам системы на основе аутентификации и авторизации. В K8S это может включать использование объектов типа NetworkPolicy для контроля сетевого доступа, а также других механизмов для управления доступом к различным ресурсам.
Эти три аспекта работают вместе, чтобы обеспечить безопасный и надежный доступ к кластеру Kubernetes. - Аутентификация / Авторизация / Управление доступом
```console
root@CKA003:~# kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kubernetes-admin@kubernetes kubernetes kubernetes-admin
root@CKA003:~# kubectl create namespace ns1
namespace/ns1 created
root@CKA003:~# kubectl create namespace ns2
namespace/ns2 created
root@CKA003:~# useradd -m -d /home/poweruser -s /bin/bash poweruser
root@CKA003:~# passwd poweruser
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
root@CKA003:~# cd /home/poweruser
root@CKA003:/home/poweruser# openssl genrsa -out poweruser.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
......................+++++
..........................................................+++++
e is 65537 (0x010001)
root@CKA003:/home/poweruser# openssl req -new -key poweruser.key -out poweruser.csr -subj "/CN=poweruser/O=ns1"
Can't load /root/.rnd into RNG
139904427348416:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/root/.rnd
root@CKA003:/home/poweruser# cat poweruser.key
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAt07RnBpZFkux9vEmSUDiHsVFtAu1FmJQjia0ls2A/fbMBt2T
...
njzqykeT5cLiixwUf6x35nF2r5VydsZMHypk6dgPgC6LikTbfsL0
-----END RSA PRIVATE KEY-----
root@CKA003:/home/poweruser# cat poweruser.csr
-----BEGIN CERTIFICATE REQUEST-----
MIICZzCCAU8CAQAwIjESMBAGA1UEAwwJcG93ZXJ1c2VyMQwwCgYDVQQKDANuczEw
...
O5+ia4aC6Hn/lMsRNYzeSK/ovjMuzH7gjnYEogG8QdpIVLFF1a1D2/S1kQ==
-----END CERTIFICATE REQUEST-----
root@CKA003:/home/poweruser# openssl x509 -req -in poweruser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out poweruser.crt -days 60
Signature ok
subject=CN = poweruser, O = ns1
Getting CA Private Key
``` root@CKA003:/home/poweruser# chmod 777 poweruser.*
root@CKA003:/home/poweruser# cd
``` root@CKA003:~# kubectl config set-credentials poweruser --client-certificate=/home/poweruser/poweruser.crt --client-key=/home/poweruser/poweruser.key
Пользователь "poweruser" создан.
root@CKA003:~# mkdir /home/poweruser/.kube
root@CKA003:~# cp .kube/config /home/poweruser/.kube
root@CKA003:~# chown -R poweruser:poweruser /home/poweruser/.kube
root@CKA003:~# su poweruser poweruser@CKA003:/root$ cd
poweruser@CKA003:~$ cd .kube/
poweruser@CKA003:~/.kube$ vi config # Откройте и отредактируйте файл /home/poweruser/.kube/config
# Удалите пользователя kubernetes-admin и его сертификаты, включая
root@CKA003:~# vi /home/poweruser/.kube/config
# Удалите следующее содержимое и измените пользователя в контексте на poweruser
#- name: kubernetes-admin
# user:# данные-ключа-клиента: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJS2xBVjZ0SGg0R3d3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TVRBNE1Ea3dOREkyTVRaYUZ3MHlNakE0TURrd05ESTJNVGhhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQTNQT2J2Ly9JK2FrQkFzR3YKeERPRlpEYnF6c1AwWCtTOExRa1dmMGhCKzBOc3dySHhQR0VTcmw0OXhhbUI4RVVod0NQTG9BTTVWZkRxOVNXWApsV1A0ZE1qM1cyclFFdmp4ZnlZZDhjbWdReTNVWndJSE1tUCtRS0NJNVdwV0tRcldlTE8rTXZUd1hjM0wwcWUyClRiMEhlQ0FjMy9FdWlZcFVvRjFrVndESGl5N3BpQTVTSVpsbGhub1Q1NjAyb3RDV0RYWDg1L09UOGRtWEViQTAKSlpkeDdhM2krT3I5dVdHQk1aaldEQms2dk02U3QxQm00MGhIcGM4VGpQSERZOVdwcldoVXZOUXpuNEtTSDdYQQpJQ1h1d3VmVVRVQXpGVWdobm5yZXc5MzFXd3NXejJpUlN6dldzUGdDOE8xMllNQmZQWGhoeXRRazFMSTdQaEVHCm1qbGw2UUlEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFGN3hOdWs5eEhtUDUydjh6REU3Uk9MTEU5cVlTMVhrd3I5Zgp2eTEvMVZKTklXV2Jlc3hQMUsvTm1JMTVJUS9TWWtoKzVoMWE4eGppRkc4dk5ia3BMNDAxUVpKTy93SEJYWU5WCkdXR0V4ZXRpdG5KSlpSam81NWN2NHpwTUNSOWZadmIvaGc3RzBCQmw2RW84MHNzSDJYdG5Ca04vV0VPY0VoZk8KQ2pFYkNGREVmbzFMRG9aTDZjZGwxU3dnTFlWZ3l6ZlQrcjdJVmNaZEVuWXZjMDhZNThLKzVPL3dMZnBaSjQxdwpVbWtQdzE3R0sxUjVUQUJrWHBRRFE5M3pwTnZ6M1k3ZUZlQTM5V2ZocGthZU4yRUpTQ3ZwdzdNaGQyTCtVUHFYCkdOSVpkNVYyOGF3d21GUUhURm9DdlZ0SUszMEFYMWQyTTkvNkpwMEUvNDdNZE1meWFNWT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= # client-certificate-data:LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBM1BPYnYvL0krYWtCQXNHdnhET0ZaRGJxenNQMFgrUzhMUWtXZjBoQiswTnN3ckh4ClBHRVNybDQ5eGFtQjhFVWh3Q1BMb0FNNVZmRHE5U1dYbFdQNGRNajNXMnJRRXZqeGZ5WWQ4Y21nUXkzVVp3SUgKTW1QK1FLQ0k1V3BXS1FyV2VMTytNdlR3WGMzTDBxZTJUYjBIZUNBYzMvRXVpWXBVb0Yxa1Z3REhpeTdwaUE1UwpJWmxsaG5vVDU2MDJvdENXRFhYODUvT1Q4ZG1YRWJBMEpaZHg3YTNpK09yOXVXR0JNWmpXREJrNnZNNlN0MUJtCjQwaEhwYzhUalBIRFk5V3ByV2hVdk5Rem40S1NIN1hBSUNYdXd1ZlVUVUF6RlVnaG5ucmV3OTMxV3dzV3oyaVIKU3p2V3NQZ0M4TzEyWU1CZlBYaGh5dFFrMUxJN1BpRUdtamxsNlFJREFRQUJBb0lCQUYvUmtYaTVMMm45dmI5NQpTWVUzcHFCb0pIb1lockRUWER2WGxoY0t1ZnFDS2ZkZy9iSG1reGhsTERxOUlPbVd3V1UyNE1aNnYzR2lzZkl3CkpFV1gvaFovVks0amF5cmZKTE8wVHdZZEgxQWkzdHJ4Q1RmMEh6M2RvS0NFOWVxRWxhL3dtd28wS00wMVF6QU8KcFVPZk4wOEQ5aUd6MFMrNmVxcTA5Wis1YWMvVUNLQWgyczNzL2hjSHlEUk9yeFpCd1JDY3RoTXlGdU03SklIaQp3dXZKTEJqZkdXVnhGNGdkWWRiMXdIMFdNZ2txanhkVDEvcWthSEE2TmtNTEZrRnZNdzRSTDdpbUdmMmcrVDBGCnB1WVorRW9oRGVtTEpCVGF5ZTM3ZjlST3pRRTBtTFNEa1E5WnRmZDBMOE5telJ2eUIzTTdXV0FtVXhaM2FuTk4KSE5RV0k1VUNnWUVBM3RNZVNUcEhyMU1YcmhzdTZ6SlNwUEh6a3hQVE95VlE3NjY5cjJ6ay9UeDNVUUFzSktoSAovNFlTWUNyTzh6Q09HY09va1EzWUNCQlJBU2dlNmp5ekR3L0duRmxzT3o4MVdIYWp0NlRjKzVzVFh3dk9EUkxrCmxCSDBHblhIbHJ0M2FzV1JBRS9xVVlzeVJhUEs4a0tzRHRidlk4RllnbzB0NHFCYnBTelo2VHNDZ1lFQS9ka1oKSGtNZG5OWHFYTk9jTnJ0YzlDaGRjeUpXR2ppMEpPQ3dSVVNyNzMxMGFhcm1JU2tOR0Q1NTNUSlhnRlBRb2t3QQpRaWNVQ2VUY0t3SkM0VUUrWEVYaEZKU3RwNmR4VDJlR1AyU2ZtMUxENUp2cWZiU2xuNE81Ni9MTTY1Ym9BbVJCCmtjMVl1M0ZjZ1BiYlRIMXI4K2FqK1IxUG5NdTBsT2ZRNUJHeUd5c0NnWUJ2MTZvSStXN0h5cjVGRHJIakxmUWIKaExKTXJaUEZ5VG94eEJURHU3WElnaFFsblIrTEdzaGdzbXdBeHh2dkp2ejhZNS8xaHV4YlI4MVE5bEZtSXllQgpOTnJzMlZtZzkxNFFWQ1JpNWlaaFIvcFdKN2U2Q2pTZk9jKzdoRWkxR00yYzB5T3Y4MnphbHpLWmo5Z3E5MW9qCmJMRGw4a001N0NFTDhveHRnUEN6eHdLQmdCQXZ6c1U2UEdJcTFkWHpmR3VWQ1BsY3RaREk2THFsVVA5bEFIaDYKUjRodU5JUmtiR1pDNnQzWDVnZHYxVnFPZmFoTHRseUJoMnFXR0YvNXRmQU5LLy9RU09qNkRoUzV2YVQxa2Y3cQoySzZiMlhmelpVRjh5bTdsbmw1b1RoN2JzWkd0ZU96bUxqbE5vanRyQWxMZlVJbnQ5QmpIZ0xNYjNqajhpenB2CjBtNmZBb0dBUGtqY0lhWE93dnhXdFhReCttWEVQWkQxUEoyeElWN240am9hNHJ4L0pqNmx6dmRhQ2xmZzlSYjIKVC81QjREcWViNC9udlA0WUpBSTR4RUxCTVI0N1EvbVBHVkFldXc0SmgyZ3RBdmx3S0RDOGliaTg0NzlKSi9qOQo2T2gzNkR1UVpoeU56QU1namxCZG5oNEk0UitYYmZZcEo2UjNSUE5jM2dWT1cvVkFPc009Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== ```Вот файл kubeconfig:```yaml
apiVersion: v1 clusters:
Затем приведите пользователя poweruser к соответствующим правам
```console
# Попытка получить pod завершится ошибкой, так как у нас нет rbac-прав для этого пользователя
poweruser@CKA003:~/.kube$ kubectl get pods
Error from server (Forbidden): pods is forbidden: User "poweruser" cannot list resource "pods" in API group "" in the namespace "default"
Приведите пользователя poweruser к соответствующим правам
root@CKA003:~# vi pod-read.yaml
root@CKA003:~# cat pod-read.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: ns1
name: pod-reader
rules:
- apiGroups: [""] # "" указывает на основной API-группу
resources: ["pods"]
verbs: ["get", "watch", "list"]
root@CKA003:~# kubectl apply -f pod-read.yaml
role.rbac.authorization.k8s.io/pod-reader created
```root@CKA003:~# vi role-binding.yaml
root@CKA003:~# cat role-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
# This role binding allows the user "poweruser" to read pods in the namespace "ns1".
# You need to already have a role named "pod-reader" in this namespace.
kind: RoleBinding
metadata:
name: read-pods
namespace: ns1
subjects:
# You can specify more than one "subject"
- kind: User
name: poweruser # "name" is case-sensitive
apiGroup: rbac.authorization.k8s.io
roleRef:
# "roleRef" points to the binding to a role / cluster role
kind: Role # this should be Role or ClusterRole
name: pod-reader # this should correspond to the name of the role or cluster role to which you want to bind
apiGroup: rbac.authorization.k8s.io```Теперь пользователь poweruser получает ошибку при попытке получить список pod в стандартном пространстве имен default.
```console
# Ошибка -- нет прав на получение списка pod в пространстве имен default
poweruser@CKA003:~/.kube$ kubectl get pods
# Возвращаемое значение: Error from server (Forbidden): pods is forbidden: User "poweruser" cannot list resource "pods" in API group "" in the namespace "default"
# Ок
poweruser@CKA003:~/.kube$ kubectl get pods -n ns1
Эксперимент: создание обычного пользователя и предоставление ему прав суперадминистратора
root@CKA003:~# openssl genrsa -out superuser.key 2048
Generating RSA private key, bk 2048 bit long modulus (2 primes)
..........................+++++
........................................................................................+++++
e is 65537 (0x010001)
root@CKA003:~# openssl req -new -key superuser.key -out superuser.csr -subj "/CN=superuser/O=system:masters"
Can't load /root/.rnd into RNG
139767359660480:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/root/.rnd
root@CKA003:~# openssl x509 -req -in superuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out superuser.crt -days 60
Signature ok
subject=CN = "superuser", O = system:masters
Getting CA Private Key
system:masters — это стандартная группа cluster-rolebinding, см. также: Как просмотреть членов субъекта с типом Group
root@CKA003:~# kubectl get clusterrolebindings -o go-template='{{range .items}}{{range .subjects}}{{.kind}}-{{.name}} {{end}} {{" - "}} {{.metadata.name}} {{"\n"}}{{end}}' | grep "^Group-system:masters"
Group-system:masters - cluster-admin
```console
root@CKA003:~# kubectl config set-credentials superuser --client-certificate=superuser.crt --client-key=superuser.key
Пользователь "superuser" установлен.
root@CKA003:~# tail -f .kube/config
...
- name: poweruser
user:
client-certificate: /home/poweruser/poweruser.crt
client-key: /home/poweruser/poweruser.key
- name: superuser
user:
client-certificate: /root/superuser.crt
client-key: /root/superuser.key
```
root@CKA003:~# kubectl config set-context superuser-context --cluster=kubernetes --user=superuser
Контекст "superuser-context" создан.
root@CKA003:~# kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kubernetes-admin@kubernetes kubernetes kubernetes-admin
superuser-context kubernetes superuser
root@CKA003:~# kubectl config use-context superuser-context
Переключен на контекст "superuser-context".
root@CKA003:~# kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
kubernetes-admin@kubernetes kubernetes kubernetes-admin
* superuser-context kubernetes superuser
root@CKA003:~# kubectl get pods
NAME READY STATUS RESTARTS AGE
dnsutils 1/1 Running 4 4h49m
web-0 0/1 Pending 0 149m
```
- Эксперимент: создание Service Account и привязка роли
```console
root@CKA003:~# kubectl create serviceaccount sa-cluster-admin --namespace=kube-system
serviceaccount/sa-cluster-admin создан
``` root@CKA003:~# kubectl get secret --all-namespaces | grep sa-cluster-admin
kube-system sa-cluster-admin-token-k9xfp kubernetes.io/service-account-token 3 53s
```
root@CKA003:~# kubectl describe secret -n kube-system sa-cluster-admin-token-k9xfp
Name: sa-cluster-admin-token-k9xfp
Namespace: kube-system
Labels: <none>
Annotations: kubernetes.io/service-account.name: sa-cluster-admin
kubernetes.io/service-account.uid: 11deb8dd-5625-4d75-ad44-3beef1bcd995
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1025 байт
namespace: 11 байт
token: eyJhbGciOiJSUzI1NiIsImtpZCI6InRBUkJ6bkxQMHNHSi1MejR4T2ZtYk43b1Y0S2M3MXZOMTMtQmtOaHpsbXMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJzYS1jbHVzdGVyLWFkbWluLXRva2VuLWs5eGZwIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InNhLWNsdXN0ZXItYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIxMWRlYjhkZC01NjI1LTRkNzUtYWQ0NC0zYmVlZjFiY2Q5OTUiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06c2EtY2x1c3Rlci1hZG1pbiJ9.Dr1aOVdwAXO_BPXlJAohKBjoxRhMmTWyfVy2AP3-D0V-2jzdzWKoEP_17wnAS3FP-hxuOtTr3XWN0zM4oAI8-CeXtP7AdB0sqZ9P7Wnp2s88DqDUNK0JUuYGke3js9xd44Bt5vhtRovNEMYEnLXj_NLOunW33f4g46ep4NvQpNGTd48BcgzFhiiWuXLKKGGoOZGrWlkXqyofE4li83B3D08oW-hjP4S0JBBXqmzpa0_PYi-hkPbirmn9J7F-oQd0So05uAzZROHSd7n8INlYwbJx2zRF8PKipscxu47ddEumr6R9b8qDDVolP5iawqFPeDTt9lOY7OdgEaVcL651UQ
root@CKA003:~# vi sa-cluster-admin-rolebinding.yaml root@CKA003:~# cat sa-cluster-admin-rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
# This cluster role binding allows any user from the "manager" group to read secrets in any namespace.
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: ServiceAccount
name: sa-cluster-admin
namespace: kube-system
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
root@CKA003:~# kubectl create -f sa-cluster-admin-rolebinding.yaml
clusterrolebinding.rbac.authorization.k8s.io/read-secrets-global created
Token can be directly written to the file `.kube/config`:
```bash
kubectl config set-credentials аккаунт --token=eyJhbGciOiJSUzI1NiIsImtpZCI6InRBUkJ6bkxQMHNHSi1MejR4T2ZtYk43b1Y0S2M3MXZOMTMtQmtOaHpsbXMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJzYS1jbHVzdGVyLWFkbWluLXRva2VuLWs5eGZwIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InNhLWNsdXN0ZXItYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIxMWRlYjhkZC01NjI1LTRkNzUtYWQ0NC0zYmVlZjFiY2Q5OTUiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06c2EtY2x1c3Rlci1hZG1pbiJ9.Dr1aOVdwAXO_BPXlJAohKBjoxRhMmTWyfVy2AP3-D0V-2jzdzWKoEP_17wnAS3FP-hxuOtTr3XWN0zM4oAI8-CeXtP7AdB0sqZ9P7Wnp2s88DqDUNK0JUuYGke3js9xd44Bt5vhtRovNEMYEnLXj_NLOunW33f4g46ep4NvQpNGTd48BcgzFhiiWuXLKKGGoOZGrWlkXqyofE4li83B3D08oW-hjP4S0JBBXqmzpa0_PYi-hkPbirmn9J7F-oQd0So05uAzZROHSd7n8INlYwbJx2zRF8PKipscxu47ddEumr6R9b8qDDVolP5iawqFPeDTt9lOY7OdgEaVcL651UQ
kubectl config set-context аккаунт-контекст --cluster=kubernetes --user=аккаунт
kubectl config use-context аккаунт-контекст
```
## Урок 05: Расписание K8S### 5.1 Как развернуть кластер K8S с несколькими узлами? - Ссылки
- Официальная документация: [Как использовать kubeadm для создания высокодоступного кластера?](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/)
- [Как развернуть многоподключенное K8S окружение?](deploy-k8s-manual.md)
- [Как развернуть K8S окружение с двойным стеком и высокой доступностью?](basic.md)
- [Развертывание высокодоступного Kubernetes кластера на AWS](deploy-aws-ha-k8s-cluster.md)
- [руководства по реализации архитектуры openshift-container-platform-reference](https://blog.openshift.com/openshift-container-platform-reference-architecture-implementation-guides/)  
- Нетворкирование с несколькими плоскостями

- Шаги
1. Получение токена и ca_hash на узле master
```console
root@ckamaster003:~# kubeadm token create
b6k3qj.avofghaucefqe0a8
root@ckamaster003:~# kubeadm token list | grep -v TOKEN | awk '{print $1}' | head -n -1
b6k3qj.avofghaucefqe0a8
root@ckamaster003:~# openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
d7d0906ebe29f607587e404ef6c393169a51e5f6c81e22a2a48f30ef8702e12a
root@ckamaster003:~# ifconfig | grep eth0 -A 1
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.31.43.105 netmask 255.255.240.0 broadcast 172.31.47.255
```
2. Использование команды kubeadm для добавления нового узла в кластер k8s, сначала сгенерировать команду на узле master
```bash
kubeadm token create
master_ip=$(ifconfig | grep eth0 -A 1 | grep inet | awk '{print $2}')
token=$(kubeadm token list | grep -v TOKEN | awk '{print $1}' | head -n 1)
ca_hash=$(openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //')
echo kubeadm join $master_ip:6443 --token $token --discovery-token-ca-cert-hash sha256:$ca_hash
```
3. Затем скопировать сгенерированную команду на узел worker и выполнить её, **перед выполнением на узле worker должны быть установлены Docker и kubeadm**
- См. раздел 1.6, [Настройка Docker на Ubuntu 18.04](#16-эксперимент-docker-quick-start)
- См. раздел 2.7, [Установка kubeadm](#27-эксперимент-установки-k8s)
- Затем скопировать сгенерированную команду на узел worker и выполнить её: `kubeadm join $master_ip:6443 --token $token --discovery-token-ca-cert-hash sha256:$ca_hash` 4. Настройка kubectl на новом узле
```bash
mkdir -p $HOME/.kube
scp root@$master_ip:/etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
```
5. Затем на новом узле можно увидеть, что узел готов к работе с помощью команды kubectl
```console
root@ckaslave003:~# kubectl get nodes
ИМЯ СТАТУС РОЛИ ВОЗРАСТ ВЕРСИЯ
ckamaster003 Ready master 20m v1.18.3
ckaslave003 Ready <none> 33s v1.18.3
```
### 5.2 Как развернуть приложение на определённом узле?
- См. также: [Labels and Selectors](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/)
```yaml
apiVersion: v1
kind: Pod
metadata:
name: label-demo
labels:
environment: production
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
```
```bash
# Создайте объект pod с метками label-pod.yaml, содержимое которого указано выше
kubectl apply -f label-pod.yaml
```
```console
root@ckatest:~# kubectl get pods -l environment=production
ИМЯ ГОТОВ СТАТУС ПЕРЕЗАПУСКИ ВОЗРАСТ
label-demo 1/1 Running 0 4m16s
root@ckatest:~# kubectl get pods -l environment=production,tier=frontend
Нет ресурсов в пространстве имен default.
root@ckatest:~# kubectl get pods -l 'environment in (production),tier in (frontend)'
Нет ресурсов в пространстве имен default.
root@ckatest:~# kubectl get pods -l 'environment in (production, qa)'
ИМЯ ГОТОВ СТАТУС ПЕРЕЗАПУСКИ ВОЗРАСТ
label-demo 1/1 Running 0 4m42s
root@ckatest:~# kubectl get pods -l 'environment,environment notin (frontend)'
ИМЯ ГОТОВ СТАТУС ПЕРЕЗАПУСКИ ВОЗРАСТ
label-demo 1/1 Running 0 4m50s
```- См. также: [Assigning Pods to Nodes](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/)
- Эксперимент:
1. Как выбрать узел для запуска pod на основе меток? (см. пример выше)
1. Как выбрать узел для запуска pod по имени узла?
```yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
nodeName: foo-node # расписание pod на определённый узел
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
```
Node Selector на самом деле является узловой симметрией, которая используется для размещения pod на определённых узлах.
### 5.3 Что такое Taints & Toleration?
- Ссылка: [Taints и Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/)
- Эксперимент
Примените taint к узлу master
```bash
kubectl taint nodes k8s-masterXXX key=value:NoSchedule
```
```yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx5
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
node-role.kubernetes.io/master: ""
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"
```
- Если не использовать nodeSelector, а вместо этого использовать nodeName, можно проигнорировать taint NoSchedule, и под будет распределен. Однако после распределения он будет вытеснен taint NoExecute.
```yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
nodeName: ckamaster003
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
```
Taint фактически представляет собой противоположность узловому сродству, запрещающую размещение pod'ов на узлах с taint.Комбинация Toleration и Taint позволяет определенным узлам размещать только определенные pod'ы, обеспечивая специализацию узлов.
### 5.4 Что такое Node Affinity?
- Ссылка: [Назначение подов на узлы с помощью Node Affinity](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/)
Рассуждение:
1. Каковы отношения между Node Affinity и Node Selector?
### 5.5 Что такое Pod Affinity?
- [Межузловое сродство и противоположное сродство](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity)
### 5.6 Эксперимент: Распределение подов
## Урок 06: Хранилище K8S
### 6.1 Что такое ConfigMap и Secret?
- [ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/)
- Ссылка: [Настройка пода для использования ConfigMap](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/)
- Ссылка: [Настройка Redis с помощью ConfigMap](https://kubernetes.io/docs/tutorials/configuration/configure-redis-using-configmap/)
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: example
data:
example.property.1: hello
example.property.2: world
example.property.file: |-
property.1=value-1
property.2=value-2
property.3=value-3
```
```yaml
apiVersion: v1
kind: Pod
metadata:
name: configmap-demo-pod
spec:
containers:
- name: nginx
image: nginx
env:
- name: TEST1
valueFrom:
configMapKeyRef:
name: example
key: example.property.2
volumeMounts:
- name: config
mountPath: "/config"
readOnly: true
volumes:
- name: config
configMap:
name: example
root@ckamaster003:~# kubectl exec -it configmap-demo-pod /bin/sh
# env | grep TEST
TEST1=world
# ls /config
example.property.1 example.property.2 example.property.file
```- [Секрет](https://kubernetes.io/docs/concepts/configuration/secret/)
Секреты и ConfigMap используются для конфигурации, но Секрет шифрует или кодирует содержимое.
```bash
# Создание двух секретов
kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests
# Создание двух pod, которые используют указанные секреты в качестве конфигурационных файлов
cat <<EOF > pod.yaml
apiVersion: v1
kind: List
items:
- kind: Pod
apiVersion: v1
metadata:
name: prod-db-client-pod
labels:
name: prod-db-client
spec:
volumes:
- name: secret-volume
secret:
secretName: prod-db-secret
containers:
- name: db-client-container
image: nginx
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
- kind: Pod
apiVersion: v1
metadata:
name: test-db-client-pod
labels:
name: test-db-client
spec:
volumes:
- name: secret-volume
secret:
secretName: test-db-secret
containers:
- name: db-client-container
image: nginx
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
EOF
``` cat <<EOF >> kustomization.yaml
ресурсы:
- pod.yaml
EOF
kubectl apply -k .
```
Затем войдите в контейнер, чтобы увидеть, как секрет был отображен в виде файлов
```console
[root@k8slab001 ~]# kubectl exec -it prod-db-client-pod -- sh
# cd /etc/secret-volume
# ls
password username
# cat password
Y4nys7f11
# cat username
produser
# exit
```
См. также: <https://kubernetes.io/ru/docs/concepts/configuration/secret/#use-case-as-container-environment-variables> для отображения секрета в виде переменных окружения в pod### 6.2 Что такое PV / PVC?
- [Типы томов](https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes)
- [Persistent Volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/)
- [Настройка pod для использования тома для хранения](https://kubernetes.io/docs/tasks/configure-pod-container/configure-volume-storage/)
- [Настройка pod для использования PersistentVolume для хранения](https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/) обратите внимание на то, что hostPath соответствует пути на узле, поэтому убедитесь, что вы знаете, на каком узле запускается pod. Лучше всего заранее использовать taint для slave узла или использовать node selector для указания запуска pod на master узле, чтобы избежать проблем.
### 6.3 Что такое Storage Class?
- [Storage Classes](https://kubernetes.io/docs/concepts/storage/storage-classes/)
- [Динамическое выделение томов](https://kubernetes.io/docs/concepts/storage/dynamic-provisioning/)
- [NFS](../src/config-lab/README.md#3-интеграция-nfs-хранилища)
- [Динамическое локальное экспериментирование](https://gitee.com/wu-wen-xiang/lab-kubernetes/blob/master/doc/kubernetes-best-practices.md#45-local-%E5%92%8C%E5%8A%A8%E6%80%81%E5%88%86%E9%85%8D)
- [NFS экспериментирование](https://gitee.com/wu-wen-xiang/lab-kubernetes/blob/master/doc/kubernetes-best-practices.md#42-%E5%AF%B9%E6%8E%A5-nfs-%E5%92%8C-nas)
### 6.4 Эксперимент: ConfigMap / Secret / PV & PVC / StorageClass
## Урок 07: Service
### 7.1 Как реализован Service на уровне реализации?
- [Service](https://kubernetes.io/docs/concepts/services-networking/service/)
- [Подключение приложений с помощью Service](https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/)
- [Руководство по модели сетей Kubernetes](https://sookocheff.com/post/kubernetes/understanding-kubernetes-networking-model/)
### 7.2 Эксперимент: публикация сервиса- Адресное пространство кластера (Cluster IP)
- Полное имя домена сервиса (Service FQDN)
- Узел с портом (Nodeport)
- Тип балансера (LB Type Service)
```bash
# Отметить slave узел, так как в некоторых средах не разрешены туннели, мы вынуждены запускать все pod на master узле
kubectl taint node ckaslave001 key=value:NoExecute
# Создать Deployment
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/service/networking/run-my-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 1
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
# Создать Service
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/service/networking/nginx-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
root@ckamaster001:~# kubectl get svc --all-namespaces -o wide
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8h <none>
default my-nginx ClusterIP 10.98.172.84 <none> 80/TCP 36m run=my-nginx
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 8h k8s-app=kube-dns
root@ckamaster001:~# dig @10.96.0.10 my-nginx.default.svc.cluster.local
; <<>> DiG 9.11.3-1ubuntu1.12-Ubuntu <<>> @10.96.0.10 my-nginx.default.svc.cluster.local
; (1 server found)
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23475
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 2661e0af4b0ce87e (echoed)
;; QUESTION SECTION:
;my-nginx.default.svc.cluster.local. IN A
;; ОТВЕТНАЯ СЕКЦИЯ:
my-nginx.default.svc.cluster.local. 30 IN A 10.98.172.84
```;; ВРЕМЯ ЗАПРОСА: 0 msec
;; СЕРВЕР: 10.96.0.10#53(10.96.0.10)
;; ВРЕМЯ: Сб Июн 13 16:15:23 CST 2020
;; РАЗМЕР СООБЩЕНИЯ: 125
### 7.3 Что такое Ingress?
- [Ingress Controller](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/)
- [Установка Nginx Ingress Controller](https://kubernetes.github.io/ingress-nginx/deploy/#bare-metal)
```bash
# Скачать файл конфигурации ingress controller
# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml
wget https://gitee.com/dev-99cloud/training-kubernetes/raw/master/src/amd-lab/deploy.yaml
```
В новых версиях по умолчанию не слушаются порты 80 и 443, их нужно настроить самостоятельно
```bash
# Проверить, заняты ли порты
# lsof -i :xxx
netstat -putln | grep 80
netstat -putln | grep 443
# Добавить следующие строки в конфигурацию, чтобы слушать локальные порты
hostNetwork: true
# spec:
# hostNetwork: true
# containers:
# - name: nginx
# image: nginx:1.7.9
# Обычно порт 443 занят Calico, порт 80 не занят, можно закомментировать строки в конфигурации, относящиеся к порту 443, и контроллер перестанет слушать этот порт
# Установить ingress controller
kubectl apply -f deploy.yaml
# Проверить
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
# Увидим, что состояние EXTERNAL-IP для ingress-nginx-controller — pending, нужно добавить externalIPs вручную
# Добавить externalIPs в конфигурацию сервиса ingress-nginx-controller, 10.0.0.118 — IP узла:
# externalIPs:
# - 10.0.0.118
# spec:
# externalIPs:
# - 192.168.132.253
# ports:
# - name: highport
# nodePort: 31903
kubectl edit svc ingress-nginx-controller -n ingress-nginx
```
- [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) - Развернуть сервисы-backend
```console
[root@iZuf6g226c4titrnrwds2tZ ~]# vim deploy-demo.yaml
```
```yaml
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
selector:
app: myapp
release: canary
ports:
- name: http
targetPort: 80
port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-backend-pod
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v2
ports:
- name: http
containerPort: 80
```
```console
[root@iZuf6g226c4titrnrwds2tZ ~]# kubectl apply -f deploy-demo.yaml
[root@iZuf6g226c4titrnrwds2tZ ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-backend-pod-58b7f5cf77-krmzh 1/1 Running 2 17h
myapp-backend-pod-58b7f5cf77-vqlgl 1/1 Running 2 17h
myapp-backend-pod-58b7f5cf77-z7j7z 1/1 Running 2 17h
```
- Предоставление сервиса через ingress-controller и создание для него сервиса
```bash
# Загрузка yaml-файла
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml
vim service-nodeport.yaml
```
```yaml
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
nodePort: 30080
- name: https
port: 443
targetPort: 443
protocol: TCP
nodePort: 30443
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
``` ---
```console
[root@iZuf6g226c4titrnrwds2tZ ~]# kubectl apply -f service-nodeport.yaml
[root@iZuf6g226c4titrnrwds2tZ ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.105.153.191 <none> 80:30080/TCP,443:30443/TCP 9h
```
- Развертывание Ingress
```console
[root@iZuf6g226c4titrnrwds2tZ ~]# vim ingress-myapp.yaml
```
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-myapp
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myapp.test.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp
port:
number: 80
```
```console
[root@iZuf6g226c4titrnrwds2tZ ~]# kubectl apply -f ingress-myapp.yaml
[root@iZuf6g226c4titrnrwds2tZ ~]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-myapp <none> myapp.test.com 10.105.153.191 80 17h
```
- Результат тестирования
```bash
# Изменение локального файла hosts
sudo vi /etc/hosts
# Добавление
xxx.xxx.xxx.xxx myapp.test.com
# Доступ через терминал
curl http://myapp.test.com
# Результат
Привет MyApp | Версия: v2 | <a href="hostname.html">Имя хоста</a>
# При внешнем доступе может возникнуть проблема с отсутствием регистрации сайта, несколько попыток помогут
# Внутри сети также требуется настройка hosts для доступа по доменному имени
```
- Проблемы с подключением к k8s.gcr.io приводят к неудаче при загрузке образа
- Скачайте файл yaml на локальную машину
- Найдите соответствующий образ на Docker Hub
- Измените соответствующий образ в файле на найденный на Docker Hub, например: ```console
#image: k8s.gcr.io/ingress-nginx/controller:v0.47.0@sha256:52f0058bed0a17ab0fb35628ba97e8d52b5d32299fbc03cc0f6c7b9ff036b61a
image: willdockerhub/ingress-nginx-controller:v0.47.0
```
- Примените изменения с помощью команды `kubectl apply -f xxx`
## Урок 08: Расширенные возможности
### 8.1 Мониторинг, логирование, отладка
- Мониторинг: Grafana / Prometheus / AlertManager
- Логирование: ElasticSearch / Fluent (Logstash) / Kibana
- Отладка:
- Как сделать дамп сетевого трафика для pod?
```bash
# Просмотр node, на котором запущен указанный pod
kubectl describe pod <pod> -n <namespace>
# Получение PID контейнера
docker inspect -f {{.State.Pid}} <container>
# Вход в сетевой namespace контейнера
nsenter --target <PID> -n
# Использование tcpdump для дампа пакетов, указание eth0
tcpdump -i eth0 tcp and port 80 -vvv
# Или дамп пакетов и запись в файл
tcpdump -i eth0 -w ./out.cap
# Выход из nsenter, не забудьте выйти!
exit
```
- Инструменты отладки
```yaml
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
labels:
app: demo-pod
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
env:
- name: DEMO_GREETING
value: "Привет из окружения"
- name: DEMO_FAREWELL
value: "Такая сладкая скорбь"
- name: busybox
image: busybox
args:
- sleep
- "1000000"
```
```console
root@ckatest001:~# kubectl exec -it demo-pod -c busybox -- /bin/sh
/ # ping 192.168.209.193
PING 192.168.209.193 (192.168.209.193): 56 data bytes
64 bytes from 192.168.209.193: seq=0 ttl=63 time=0.099 ms
64 bytes from 192.168.209.193: seq=1 ttl=63 time=0.093 ms
64 bytes from 192.168.209.193: seq=2 ttl=63 time=0.089 ms
``` ```console
root@ckalab001:~# tcpdump -i eth0 udp
12:34:10.972395 IP 45.77.183.254.vultr.com.42125 > 45.32.33.135.vultr.com.4789: VXLAN, flags [I] (0x08), vni 4096
IP 192.168.208.4 > 192.168.209.193: ICMP echo request, id 3072, seq 0, length 64
12:34:10.972753 IP 45.32.33.135.vultr.com.41062 > 45.77.183.254.vultr.com.4789: VXLAN, flags [I] (0x08), vni 4096
IP 192.168.209.193 > 192.168.208.4: ICMP echo reply, id 3072, seq 0, length 64
12:34:11.972537 IP 45.77.183.254.vultr.com.42125 > 45.32.33.135.vultr.com.4789: VXLAN, flags [I] (0x08), vni 4096
IP 192.168.208.4 > 192.168.209.193: ICMP echo request, id 3072, seq 1, length 64
```
На Алибаба-клауде Calico/Flannel VXLAN модифицированы в маршрутизационные протоколы, поэтому требуется добавление маршрутов в VPC для каждого узла. Каждый узел получает маршрут для своего IP-адреса и сегмента подсети pod. [Эта статья KB](https://yq.aliyun.com/articles/704175) очень нечетко формулирует, что VXLAN не поддерживается, а вместо этого используется модифицированный VXLAN, реализованный с использованием маршрутизации. Обычный VXLAN:
```console
root@ckalab001:~# ip r
default via 45.77.182.1 dev ens3 proto dhcp src 45.77.183.254 metric 100
192.168.208.1 dev cali65a032ad3e5 scope link
192.168.209.192/26 via 192.168.209.192 dev vxlan.calico onlink
```
```console
root@ckalab001:~# ip a
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 56:00:02:d8:35:5a brd ff:ff:ff:ff:ff:ff
inet 45.77.183.254/23 brd 45.77.183.255 scope global dynamic ens3
valid_lft 73639sec preferred_lft 73639sec
inet6 fe80::5400:2ff:fed8:355a/64 scope link
valid_lft forever preferred_lft forever
4: cali65a032ad3e5@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1410 qdisc noqueue state UP group default
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::ecee:eeff:feee:eeee/64 scope link
valid_lft forever preferred_lft forever
9: vxlan.calico: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1410 qdisc noqueue state UNKNOWN group default
link/ether 66:f1:80:3e:ea:c6 brd ff:ff:ff:ff:ff:ff
inet 192.168.208.0/32 brd 192.168.208.0 scope global vxlan.calico
valid_lft forever preferred_lft forever
inet6 fe80::64f1:80ff:fe3e:eac6/64 scope link
valid_lft forever preferred_lft forever
```
Алибаба облако модифицированное VXLAN: `192.168.209.192/26 через 172.31.43.146 dev eth0 proto 80 onlink`, где 80 — это протокол маршрутизации IGRP. Поэтому при отправке пакетов ping между контейнерами на разных узлах с помощью tcpdump пакеты TCP не отлавливаются, а пакеты ICMP отлавливаются.```console
root@ckalab001:~# ip r
default через 172.31.47.253 dev eth0 proto dhcp src 172.31.43.145 metric 100
192.168.208.1 dev cali77bffbebec8 scope link
192.168.209.192/26 через 172.31.43.146 dev eth0 proto 80 onlink
root@ckalab001:~# ip a
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:16:3e:08:2e:5f brd ff:ff:ff:ff:ff:ff
inet 172.31.43.145/20 brd 172.31.47.255 scope global dynamic eth0
valid_lft 315356000sec preferred_lft 315356000sec
inet6 fe80::216:3eff:fe08:2e5f/64 scope link
valid_lft forever preferred_lft forever
4: cali77bffbebec8@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1410 qdisc noqueue state UP group default
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::ecee:eeff:feee:eeee/64 scope link
valid_lft forever preferred_lft forever
8: vxlan.calico: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1410 qdisc noqueue state UNKNOWN group default
link/ether 66:f1:80:3e:ea:c6 brd ff:ff:ff:ff:ff:ff
inet 192.168.208.0/32 brd 192.168.208.0 scope global vxlan.calico
valid_lft forever preferred_lft forever
inet6 fe80::64f1:80ff:fe3e:eac6/64 scope link
valid_lft forever preferred_lft forever
HPA (Horizontal Pod Autoscaler) — это компонент Kubernetes, который автоматически масштабирует количество подов в зависимости от нагрузки. CA (Cluster Autoscaler) — это компонент Kubernetes, который автоматически масштабирует количество узлов в кластере в зависимости от потребностей приложений. VA (Vertical Pod Autoscaler) — это компонент Kubernetes, который автоматически масштабирует ресурсы подов в зависимости от потребностей приложений.- Как понять HPA / CA / VPA?
mkdir metrics
cd metrics
# Скачать все yaml-файлы из соответствующего репозитория на GitHub
# for file in auth-delegator.yaml auth-reader.yaml metrics-apiservice.yaml metrics-server-deployment.yaml metrics-server-service.yaml resource-reader.yaml ; do wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/metrics-server/$file;done
# В новых версиях могут возникнуть проблемы с прохождением проверки состояния, поэтому рекомендуется использовать ту же версию metrics server, что и ваш kubernetes
# Скачать версию v1.20.1 с внутреннего репозитория
for file in auth-delegator.yaml auth-reader.yaml metrics-apiservice.yaml metrics-server-deployment.yaml metrics-server-service.yaml resource-reader.yaml ; do wget https://gitee.com/dev-99cloud/training-kubernetes/raw/master/src/amd-lab/metrics-server/$file;done
kubectl apply -f .
Измените metrics-server-deployment.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: metrics-server
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
---
apiVersion: v1
kind: ConfigMap
metadata:
name: metrics-server-config
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: EnsureExists
data:
NannyConfiguration: |-
apiVersion: nannyconfig/v1alpha1
kind: NannyConfiguration
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: metrics-server-v0.3.6
namespace: kube-system
labels:
k8s-app: metrics-server
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
version: v0.3.6
spec:
selector:
matchLabels:
k8s-app: metrics-server
version: v0.3.6
template:
metadata:
name: metrics-server
labels:
k8s-app: metrics-server
version: v0.3.6
spec:
securityContext:
seccompProfile:
type: RuntimeDefault
``` priorityClassName: system-cluster-critical
serviceAccountName: metrics-server
nodeSelector:
kubernetes.io/os: linux
containers:
- name: metrics-server
# image: k8s.gcr.io/metrics-server-amd64:v0.3.6
image: opsdockerimage/metrics-server-amd64:v0.3.6
command:
- /metrics-server
- --metric-resolution=30s
# Эти строки нужно удалить для кластеров, отличных от GKE, и когда GKE поддерживает аутентификацию на основе токенов.
# - --kubelet-port=10255
# - --deprecated-kubelet-completely-insecure=true
- --kubelet-insecure-tls
- --kubelet-preferred-address-types=InternalIP
# - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
ports:
- containerPort: 443
name: https
protocol: TCP
- name: metrics-server-nanny
# image: k8s.gcr.io/addon-resizer:1.8.11
image: opsdockerimage/addon-resizer:1.8.11
resources:
limits:
cpu: 100m
memory: 300Mi
requests:
cpu: 5m
memory: 50Mi
environment:
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumeMounts:
- name: metrics-server-config-volume
mountPath: /etc/config
command:
- /pod_nanny
- --config-dir=/etc/config
# - --cpu={{ base_metrics_server_cpu }}
- --extra-cpu=0.5m
# - --memory={{ base_metrics_server_memory }}
# - --extra-memory={{ metrics_server_memory_per_node }}Mi
- --threshold=5
- --deployment=metrics-server-v0.3.6
- --container=metrics-server
- --период-мониторинга=300000
- --оценка=экспоненциальная
# Определяет наименьший кластер (определенный количеством узлов)
# ресурсы будут масштабироваться.
# - --minClusterSize={{ metrics_server_min_cluster_size }}
- --minClusterSize=2
# Использует метрики kube-apiserver для избежания периодического перечисления узлов.
- --использовать-метрики=true
тома:
- имя: metrics-server-config-volume
конфиг_карта:
имя: metrics-server-config
терпимости:
- ключ: "CriticalAddonsOnly"
оператор: "Exists"
``` Измените resource-reader.yaml ```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: system:metrics-server
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
rules:
- apiGroups:
- ""
resources:
- pods
- nodes
# Add nodes/stats
- nodes/stats
- namespaces
verbs:
- get
- list
- watch
- apiGroups:
- "apps"
resources:
- deployments
verbs:
- get
- list
- update
- watch
- nonResourceURLs:
- /metrics
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:metrics-server
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:metrics-server
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
Проверьте доступность метрик
# Проверьте, работают ли pod-ы
kubectl get pods -n kube-system
# Проверьте api-versions, обычно должны появиться метрики metrics.k8s.io/v1beta1
kubectl api-versions
# Проверьте мониторинг узлов
kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
izuf6g226c4titrnrwds2tz 129m 6% 1500Mi 42%
# Проверьте мониторинг pod-ов
kubectl top pods
NAME CPU(cores) MEMORY(bytes)
myapp-backend-pod-58b7f5cf77-krmzh 0m 1Mi
myapp-backend-pod-58b7f5cf77-vqlgl 0m 1Mi
myapp-backend-pod-58b7f5cf77-z7j7z 0m 1Mi
Если метрики недоступны, ошибка может быть "unable to fully collect metrics: unable to fully scrape metrics from source kubelet_summary". Можно попробовать изменить сертификаты
mkdir certs; cd certs
cp /etc/kubernetes/pki/ca.crt ca.pem
cp /etc/kubernetes/pki/ca.key ca-key.pem
``` Создайте файл kubelet-csr.json
```json
{
"CN": "kubernetes",
"hosts": [
"127.0.0.1",
"<node_name>",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [{
"C": "RU",
"ST": "Moscow",
"L": "City",
"O": "Org",
"OU": "Unit"
}]
}
Создайте файл ca-config.json```json { "signing": { "default": { "expiry": "8760h" }, "profiles": { "kubernetes": { "usages": [ "signing", "key encipherment", "server auth", "client auth" ], "expiry": "8760h" } } } }
Обновить сертификаты
```bash
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem --config=ca-config.json -profile=kubernetes kubelet-csr.json | cfssljson -bare kubelet
scp kubelet.pem <nodeip>:/var/lib/kubelet/pki/kubelet.crt
scp kubelet-key.pem <nodeip>:/var/lib/kubelet/pki/kubelet.key
systemctl restart kubelet
Настроить Docker-образ
FROM php:5-apache
COPY index.php /var/www/html/index.php
RUN chmod a+rx index.php
Содержимое файла index.php:
<?php
$x = 0.0001;
for ($i = 0; $i <= 1000000; $i++) {
$x += sqrt($x);
}
?>
Настроить Deployment для запуска образа и экспонирования сервиса
php-apache.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
replicas: 1
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
#image: k8s.gcr.io/hpa-example
image: 0layfolk0/hpa-example
ports:
- containerPort: 80
resources:
limits:
cpu: 50m
requests:
cpu: 20m
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
Создать HPA
# В процессе эксперимента изменения копий, нагрузки на процессор и т.д. требуют некоторого времени и не изменяются мгновенно, обычно это занимает несколько минут
# Создайте HPA для управления Deployment из предыдущего шага, чтобы количество копий поддерживалось в диапазоне от 1 до 10, с средним использованием процессора 50%
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache autoscaled
# Проверьте состояние Autoscaler
kubectl get hpa
# Запустите контейнер в новом терминале, увеличивая нагрузку
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
# Вернитесь в старый терминал
# Проверьте нагрузку на процессор, она должна увеличиться
kubectl get hpa
# Проверьте количество копий Deployment, оно должно увеличиться
kubectl get deployment php-apache
# Остановите выполнение контейнера в новом терминале (Ctrl+C), проверьте состояние нагрузки в старом терминале, использование процессора должно упасть до 0, количество копий должно стать равно 1
kubectl get hpa
kubectl get deployment php-apache
# During the experiment, changes in the number of copies, processor load, and other factors take some time and do not change instantly; usually, this takes several minutes.
# Create an HPA to manage the Deployment from the previous step, ensuring that the number of copies is maintained within the range of 1 to 10, with an average CPU utilization of 50%.
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache autoscaled
# Check the Autoscaler status
kubectl get hpa
# Run a container in a new terminal, increasing the load
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
# Return to the old terminal
# Check the processor load, it should increase
kubectl get hpa
# Check the number of Deployment copies, it should increase
kubectl get deployment php-apache
# Stop the container execution in the new terminal (Ctrl+C), check the load status in the old terminal, the processor usage should drop to 0, and the number of copies should become 1
kubectl get hpa
kubectl get deployment php-apache
```- Kubenetes Federation vs ManageIQ
### 8.4 Как K8S обрабатывает сервисы с состоянием?
- [StatefulSet](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/)
- [Примеры StatefulSet](https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/)
- CRD & Operator, например [mariadb-operator](https://github.com/mmontes11/mariadb-operator)
### 8.5 Другие ссылки
- [Тестирование K8S](https://jimmysong.io/kubernetes-handbook/develop/testing.html)
- Установка OpenStack тестового окружения
- [vultr](https://www.vultr.com/) Ubuntu 18.04 / 20.04 Bare Metal сервер
- [Установка DevStack](https://docs.openstack.org/devstack/latest/)
- [Загрузка облачных образов](https://docs.openstack.org/image-guide/obtain-images.html)
```bash
wget http://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-2009.qcow2
wget https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64.img
wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
```
- [Загрузка образов в OpenStack](https://docs.openstack.org/murano/pike/reference/appendix/articles/image_builders/upload.html)
```bash
openstack image create --public --disk-format qcow2 --file focal-server-cloudimg-amd64.img ubuntu-20.04
openstack image create --public --disk-format qcow2 --file bionic-server-cloudimg-amd64.img ubuntu-18.04
openstack image create --public --disk-format qcow2 --file CentOS-7-x86_64-GenericCloud-2009.qcow2 centos-7.8
```
- [Включение ipip](https://www.infoq.cn/article/mqluyhvsdw8xopdwp17v)
- [Установка k3s](https://github.com/k3s-io/k3s#quick-start---install-script)
- [Пример KubeEdge](https://kubeedge.io/zh/blog/kubeedge-deployment-manual/)
## Урок 09: CKA
### 9.1 Советы по сдаче экзамена
### 9.2 Обзор тестовых вопросов
### 9.3 Практика: выполнение тестовых вопросов
## Урок 10: Часто задаваемые вопросы
1. Что такое настройка egress IP? [Решение Red Hat](https://docs.openshift.com/container-platform/4.1/networking/openshift_sdn/assigning-egress-ips.html), [Открытое решение](https://github.com/nirmata/kube-static-egress-ip)
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )