Зачем и как использовать контейнеры: разбираемся с docker, kubernetes и другими инструментами

История развития K8s

Изначально проект кубернетис был разработан корпорацией Google, одной из крупнейших Big Data компаний, для своих внутренних нужд на языке программирования Go. В середине 2014 года были опубликованы исходные коды проекта. Первый готовый релиз системы был выпущен 21 июля 2015 года (версия 1.0). Во второй половине 2015 года корпорация Google совместно с Linux Foundation организовали специальный фонд Cloud Native Computing Foundation (CNCF), которому и был передан Kubernetes в качестве начального технологического вклада .

Кубернетис, как и Docker, относится к технологиям виртуальной контейнеризации

Синтаксис

Используйте следующий синтаксис для выполнения команд в терминале:

где , , и :

  • : определяет выполняемую операцию с одним или несколькими ресурсами, например, , , , .

  • : определяет . Типы ресурсов не чувствительны к регистру, кроме этого вы можете использовать единственную, множественную или сокращенную форму. Например, следующие команды выведут одно и то же.

  • : определяет имя ресурса. Имена чувствительны к регистру. Если имя не указано, то отображаются подробности по всем ресурсам, например, .

    При выполнении операции с несколькими ресурсами можно выбрать каждый ресурс по типу и имени, либо сделать это в одном или нескольких файлов:

    • Выбор ресурсов по типу и имени:

      • Сгруппировать ресурсы, если все они одного типа: .Пример:

      • Выбор нескольких типов ресурсов по отдельности: .Пример:

    • Выбор ресурсов по одному или нескольким файлов:

      Используйте YAML вместо JSON, так так YAML удобнее для пользователей, особенно в конфигурационных файлов.Пример: kubectl get pod -f ./pod.yaml

  • : определяет дополнительные флаги. Например, вы можете использовать флаги или , чтобы указать адрес и порт API-сервера Kubernetes.

Если вам нужна помощь, выполните команду .

Конфигурация Nginx для Ingress Controller

Как я уже говорил, в моем примере под капотом Ingress контроллера работает обычный Nginx с помощью специально подготовленного DaemonSet в неймспейсе ingress-nginx.

# kubectl get all -n ingress-nginx
NAME                                 READY   STATUS    RESTARTS   AGE
pod/ingress-nginx-controller-twwpb   1/1     Running   4          75d
NAME                                      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                          AGE
daemonset.apps/ingress-nginx-controller   1         1         1       1            1           node-role.kubernetes.io/ingress=true   75d

Для того, чтобы задать глобальные параметры для ingress можно использовать configmap. Давайте для примера изменим некоторые глобальные параметры ingress. Напомню, что он запущен в namespace ingress-nginx. Добавим туда configmap для ingress-nginx и применим его.

kind: ConfigMap
apiVersion: v1
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
data:
  proxy-connect-timeout: "222"
  proxy-read-timeout: "222"
  proxy-send-timeout: "222"
# kubectl apply -f nginx-config.yaml
configmap/ingress-nginx configured

Проверяем конфигурацию ingress, выгрузив конфиг nginx в файл.

# kubectl exec -it ingress-nginx-controller-twwpb -n ingress-nginx cat /etc/nginx/nginx.conf > ~/ingress-nginx.conf

Во всех виртуальных хостах должны измениться параметры:

proxy_connect_timeout 222s;
proxy_send_timeout 222s;
proxy_read_timeout 222s;

Так же конфигурацию nginx можно задавать с помощью аннотаций. Возьмем для примера тот же магазин носок и его ingress манифест. Добавим туда аннотации.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-socks-tls
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "301"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "301"
spec:
  rules:
  - host: kuber.zeroxzed.ru
    http:
      paths:
      - backend:                                       
          serviceName: front-end                       
          servicePort: 80                              
  tls:                                                 
  - hosts:                                             
    - kuber.zeroxzed.ru                                
    secretName: socks-tls-2

Применяем.

# kubectl apply -f ingress-sock-tls.yaml 
ingress.extensions/ingress-socks-tls configured

Проверяем конфигурацию nginx. В виртуальном хосте из манифеста ingress должны установиться указанные параметры nginx.

proxy_connect_timeout 222s;
proxy_send_timeout 301s;
proxy_read_timeout 301s;

Если что-то пойдет не так, смотрите логи пода с Ingress Controller. Там будут видны ошибки. Вот пример ошибок, когда я в манифестах пытался сразу же поставить значения с секундами.

W1203 13:11:07.756139       6 configmap.go:339] unexpected error merging defaults: 2 error(s) decoding:

* cannot parse 'proxy-connect-timeout' as int: strconv.ParseInt: parsing "20s": invalid syntax
* cannot parse 'proxy-read-timeout' as int: strconv.ParseInt: parsing "20s": invalid syntax

Секунды проставляются автоматом при передаче значений в nginx. В манифестах их указывать не нужно. Я так понимаю, это особенность установки ingress controller через Kubespray. Если будете ставить через Helm или как-то еще, то это может работать по-другому. Например, во многих примерах в интернете я видел, что параметры nginx для ingress controller в манифестах указывают в виде 20s, 30m и т.д.

Основные принципы контейнеризации приложений

Для эффективной работы приложения в контейнерах недостаточно просто создать образ контейнера и запустить его. Нужно позаботиться о том, чтобы архитектура приложения и контейнера соответствовала базовым принципам контейнеризации, которые хорошо изложила компания RedHat.

1 контейнер — 1 сервис

Контейнер должен выполнять только одну функцию — не следует помещать в него все сущности, от которых зависит приложение. Следование этому принципу позволяет добиться большей переиспользуемости образов и, что самое главное, позволяет более тонко масштабировать приложение — узким местом вашего сервиса может оказаться только какая-то часть используемого стэка технологий, и разведение всех его частей по разным контейнерам позволит точечно увеличивать производительность вашего сервиса.

Неизменность образа

Все изменения внутри контейнера должны вноситься на стадии сборки образа — соблюдение этого принципа страхует вас от утраты данных при уничтожении контейнера. Неизменность контейнера также даёт возможность выполнять параллельные задачи в CI/CD системах — например, можно одновременно запустить разного рода тестирования, ускоряя тем самым процесс разработки продукта.

Утилизируемость контейнеров

Этот принцип являет собой яркий пример современной концепции «Обращайся с инфраструктурой как со скотом, не как с питомцами». Это значит, что любой контейнер может быть в любой момент уничтожен и заменён на другой без остановки обслуживания. Конфигурация контейнера в виде его образа сущностно отделена от непосредственно выполняющего работу экземпляра контейнера, что позволяет «пускать под нож» экземпляры, когда потребуется — при сбое проверки состояния контейнера, масштабировании на понижение и т. д. Соответствие этому принципу означает, что выход контейнеров из строя не должен быть новостью для вашего приложения: ротация контейнеров должна стать одним из требований к разработке.

Отчётность

Контейнер должен иметь точки проверки состояния его готовности (readiness probe) и жизнеспособности (liveness probe), предоставлять логи для отслеживания состояния запущенного в нём приложения.

Управляемость

Приложение в контейнере должно иметь возможность взаимодействовать с контролирующим его процессом — например для корректного завершения своей работы по команде извне. Это позволит аккуратно закрывать транзакции, препятствуя потере пользовательских данных в результате остановки или уничтожения контейнера.

Самодостаточность

Образ с приложением должен обладать всеми необходимыми зависимостями для работы — библиотеками, конфигами и прочим. Сервисы же к этим зависимостям не относятся, иначе это противоречило бы принципу «1 контейнер — 1 сервис». Связность контейнеров, зависящих друг от друга, можно определить с помощью инструментов оркестрирования, о чём будет рассказано ниже.

Лимитирование ресурсов

К лучшим практикам эксплуатации контейнеров относится настройка ресурсных лимитов (CPU и RAM): следование этой практике позволяет сохранять внимательное отношение к экономии ресурсов и вовремя реагировать на их избыточное потребление.

Install Kompose

We have multiple ways to install Kompose. Our preferred method is downloading the binary from the latest GitHub release.

Kompose is released via GitHub on a three-week cycle, you can see all current releases on the GitHub release page.

Alternatively, you can download the tarball.

Installing using pulls from the master branch with the latest development changes.

Kompose is in EPEL CentOS repository.
If you don’t have EPEL repository already installed and enabled you can do it by running

If you have EPEL enabled in your system, you can install Kompose like any other package.

Kompose is in Fedora 24, 25 and 26 repositories. You can install it just like any other package.

On macOS you can install latest release via Homebrew:

Превышение контейнером лимита памяти

Контейнер может превысить величину запроса памяти, если нода имеет достаточно ресурсов памяти.
Но превышение заданного ограничения памяти не допускается. Если контейнер запрашивает
больше памяти, чем ему разрешено использовать, то он становится кандидатом на удаление.
Если превышение лимита памяти продолжится, контейнер удаляется.
Если удалённый контейнер может быть перезапущен, то kubelet перезапускает его, как и в случае
любой другой неполадки в работе.

В этом упражнении создадим Pod, который попытается занять больше памяти, чем для него ограничено.
Ниже представлен конфигурационный файл для Pod’a с одним контейнером, имеющим 50 Мб
на запрос памяти и 100 Мб лимита памяти:

В разделе можно увидеть, что контейнер будет пытаться занять
250 Мб — и это значительно превышает лимит в 100 Мб.

Создадим Pod:

Посмотрим подробную информацию о Pod’е:

В этот момент контейнер уже либо запущен, либо убит.
Будем повторять предыдущую команду, пока контейнер не окажется убитым:

Посмотрим ещё более подробный вид статуса контейнера:

В выводе показано, что контейнер был убит по причине недостатка памяти (OOM):

В данном упражнении контейнер может быть перезапущен, поэтому kubelet стартует его.
Выполните следующую команду несколько раз, чтобы увидеть, как контейнер раз за разом
убивается и запускается снова:

Вывод показывает, что контейнер убит, перезапущен, снова убит, перезапущен, и т.д.:

Посмотрим подробную информацию об истории Pod’a:

Вывод показывает, что контейнер постоянно запускается и падает:

Посмотрим детальную информацию о нодах на кластере:

В выводе содержится запись о том, что контейнер убивается по причине нехватки памяти:

Удалим Pod:

Deploy реального приложения в кластер

Давайте теперь на реальном примере попробуем что-то запустить в кластере kubernetes. Я предлагаю для этого использовать демо магазин носков из этого репозитория — https://github.com/microservices-demo/microservices-demo. Там есть длиннющий yaml файл, который содержит в себе все необходимое (deployments, service и т.д.) для запуска магазина. Магазин состоит из множества компонентов, так что мы на практике убедимся, как легко и быстро можно деплоить сложные приложения в кластер.

Магазин настроен на работе в отдельном namespace — sock-shop. Его предварительно надо создать.

# kubectl create namespace sock-shop

Запускаем деплой всего проекта одной командой.

# kubectl apply -n sock-shop -f "https://raw.githubusercontent.com/microservices-demo/microservices-demo/master/deploy/kubernetes/complete-demo.yaml"

Наблюдать за поднятием подов можно командой в реальном времени.

# kubectl get pods -n sock-shop -w

После того, как они все станут Running можно проверять работу. В этом проекте не используется ingress, поэтому чтобы понять, как подключиться к магазину, надо провести небольшое расследование. Для начала посмотрим запущенные service.

# kubectl get service -n sock-shop -o wide

Нас интересует тип NodePort, так как к нему можно подключаться из вне. Видим, что порт используется 30001 и имя приложения front-end. Посмотрим, где оно запущено.

# kubectl get pod -n sock-shop -o wide

Этот pod запущен на kub-node-2. Посмотрим ее ip.

# kubectl get node -o wide

Ее ip адрес — 10.1.4.33. Значит для проверки магазина надо идти по урлу http://10.1.4.33:30001/

Вот он, наш магазин. Для удобства, можем сами доделать доступ через ingress по доменному имени. Настраиваем конфиг ingress.

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-sock
  namespace: sock-shop
spec:
  rules:
  - host: sock-shop.cluster.local
    http:
      paths:
      - backend:
          serviceName: front-end
          servicePort: 80

Не забывайте указывать нужный namespace и правильное имя сервиса, для которого настраиваем ingress. Применяем конфиг.

# kubectl apply -f ingress-sock.yaml

Смотрим, что получилось.

# kubectl get ingress -n sock-shop -o wide
NAME           HOSTS                     ADDRESS     PORTS   AGE
ingress-sock   sock-shop.cluster.local   10.1.4.39   80      29s

Редактируем файл hosts и идем в браузер проверять.

Поздравляю, ваш кластер работает, а вы теперь администратор кластера Kubernetes и инженер yaml файлов 🙂 У вас теперь будет большая дружба с лапшеподобным синтаксисом. Идите к руководству и требуйе прибавки к зарплате минимум на 30%.

Установка kubectl в Linux

Установка двоичного файла kubectl с помощью curl в Linux

  1. Загрузите последнюю версию с помощью команды:

    Чтобы загрузить определенную версию, вставьте в фрагмент команды нужную версию.

    Например, команда загрузки версии v1.19.0 для Linux будет выглядеть следующим образом:

  2. Сделайте двоичный файл kubectl исполняемым:

  3. Переместите двоичный файл в директорию из переменной окружения PATH:

  4. Убедитесь, что установлена последняя версия:

Установка с помощью стороннего пакетного менеджера

Если вы используйте Ubuntu или другой Linux-дистрибутив, в котором есть пакетный менеджер snap, kubectl доступен в виде приложения snap.

Если вы работаете в Linux и используете пакетный менеджер Homebrew, то kubectl можно через него.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector