() translation by (you can also view the original English article)
Широкомасштабные распределенные системы, состоящие из нескольких взаимодействующих сервисов, становятся все более важными. Эти системы работают на кластерах сотен, тысяч и более серверов. Разработка, развертывание и обслуживание этих систем эффективно и экономично требует серьезного порядка.
Виртуализация и, в последнее время, использование контейнеров позволяют гибко распределять ресурсы и управлять ими. Докер сделал контейнеризацию популярной. Ознакомьтесь с этой статьей Envato Tuts + для отличного введения: «Руководство автостопом по Docker и Modulus».
Google уже много лет работает над огромным программным обеспечением и центрами обработки данных в контейнерах и накопила большой опыт и знания. Kubernetes - это проект Google с открытым исходным кодом, который передает все эти знания в массы.
В этой статье я кратко исследую Докер, а затем глубоко погружаюсь в Кубернетес. Я буду использовать в качестве примера пример службы REST API Python 3. Приступим.
Служба цитат
Служба цитат - это REST API, который позволяет добавлять цитаты и получать список всех цитат. Он реализован как веб-сервис Python 3, используя отличную библиотеку hug. Сервис предоставляет один ендпоинт /quotes. Вы можете получить все цитаты или опубликовать новую цитату. Давайте добавим несколько цитат:
1 |
curl https://localhost:8000/quotes -d "quote=TV is chewing gum for the eyes. ~ Frank Lloyd Wright" |
2 |
curl http://localhost:8000/quotes -d "quote=It is better to die on your feet than live on your knees. ~ Emiliano Zapata" |
3 |
curl http://localhost:8000/quotes -d "quote=We must be very careful when we give advice to younger people: sometimes they follow it! ~ Edsger W. Dijkstra" |
Если вы перейдете по ссылке http://localhost:8000/quotes
, вы получите: [ "TV is chewing gum for the eyes. ~ Frank Lloyd Wright", "It is better to die on your feet than live on your knees. ~ Emiliano Zapata", "We must be very careful when we give advice to younger people: sometimes they follow it! ~ Edsger W. Dijkstra" ]
Если вы просто хотите просмотреть автогенерированную документацию HUG, перейдите по адресу: http://localhost:8000
1 |
{ |
2 |
"404": "The API call you tried to make was not defined. Here's a definition of the API to help you get going :)", |
3 |
"documentation": { |
4 |
"/quotes": { |
5 |
"GET": { |
6 |
"examples": [ |
7 |
"http://localhost:8000/quotes" |
8 |
], |
9 |
"outputs": { |
10 |
"content_type": "application/json", |
11 |
"format": "JSON (Javascript Serialized Object Notation)" |
12 |
} |
13 |
}, |
14 |
"POST": { |
15 |
"outputs": { |
16 |
"content_type": "application/json", |
17 |
"format": "JSON (Javascript Serialized Object Notation)" |
18 |
}, |
19 |
"inputs": { |
20 |
"quote": { |
21 |
"type": "Basic text / string value" |
22 |
} |
23 |
} |
24 |
} |
25 |
} |
26 |
} |
27 |
} |
Основы Docker
Я не буду объяснять слишком много о Docker, а просто буду применять его в сервисе цитат.
Отправляем приложение Python в контейнер
Сначала нам нужен Dockerfile. Он выполняет следующие действия:
- Делает основу из последнего образа ubuntu
- Устанавливает Python 3 и несколько других зависимостей
- Скопирует каталог quot-service
- Устанавливает зависимости quot-service из файла require.txt
- Предоставляет порт 8000
- Запустит сервис цитат через hug
1 |
FROM ubuntu:latest |
2 |
MAINTAINER Gigi Sayfan "the.gigi@gmail.com" |
3 |
RUN apt-get update -y |
4 |
RUN apt-get install -y python3 python3-pip python3-dev build-essential |
5 |
COPY . /quote-service |
6 |
WORKDIR /quote-service |
7 |
RUN pip3 install -r requirements.txt |
8 |
EXPOSE 8000 |
9 |
ENTRYPOINT hug -f app.py |
Создаем образ
Следующий шаг - создать образ Docker. Это так просто:
docker build .
Мне также нравится добавлять образам теги:
docker tag 715624b7e22a g1g1/quote-service
g1g1
- мое имя пользователя на Docker Hub.
Чтобы убедиться, что образ был успешно создан, введите:
1 |
docker ps --all |
Вы должны увидеть новый образ:
1 |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES |
2 |
715624b7e22a g1g1/quote-service "/bin/sh -c 'hug -f a" 4 hours ago Up 35 minutes 0.0.0.0:8000->8000/tcp agitated_northcutt |
Отправка образа в Docker Hub
Когда вы создаете образ, вы также можете отправить его в Docker Hub, чтобы его могли использовать другие люди (или самостоятельно на другой машине).
docker push g1g1/quote-service
Обратите внимание, что вам необходимо создать учетную запись на Docker Hub и войти в систему локально, используя:
docker login
Запуск приложения
ОК. Давайте запустим образ сервиса цитат и выставим хосту порт 8000.
docker run -i -t -p 8000 g1g1/quote-service
Вы увидите следующее: /############################################# ############################ `` .---- `` ..------- .. `` .- ---.
: / ::::: - ---------: - ::::: //. . + :::: ---- ## // оо +: - ## ---- :::: // `// :: ------- / oosoo ------- ::: //. ## ## ## ## ##### .-: ------./++ o / o -.------ :: - ` ## ## ## ## ## ----.-./+o+:..----.
.: ///. ######## ## ## ## `----.- :::::: ------
`.- :::: //. ## ## ## ## ## ####: // :: -. -: ... ----- ... ``: - ::::::.. ############: / ::::::::: -: - `` `.
::::: -. ## ## #### ###### .
-- :::::::. . :::. `` .. ::. . :: EMBRACE API OF THE FUTURE :: -.: - -:: ::- VERSION 1.9.6 :
:- -::
-::- -::- ######################################################################## Copyright (C) 2015 Timothy Edmund Crosley Under the MIT License
Serving on port 8000… ``` Очень круто. Прежде чем попытаться получить доступ к своей службе awesome quote на порту 8000, вам может потребоваться выполнить дополнительную работу в зависимости от вашей среды.
Если вы работаете под Mac OS X с помощью VirtualBox и док-машины, вам может потребоваться опубликовать порт 8000 на VirtualBox, чтобы сделать его доступным на хосте.
Предполагая, что вы попытались просмотреть http://localhost:8000/quotes
. О нет. Внутренняя ошибка сервера! Что случилось?
Давайте посмотрим на код:
1 |
redis_host = os.environ.get('QUOTE_STORE_SERVICE_HOST', 'localhost') |
2 |
redis_server = redis.StrictRedis(host=redis_host, port=6379, db=0) |
Служба цитат пытается подключиться к серверу redis. Адрес хоста может быть настроен как переменная среды, и если он не установлен, он будет по умолчанию установлен на localhost. К сожалению, redis не установлен по умолчанию, и он не запускается внутри контейнера. Давайте исправим это временно. Чтобы получить доступ к оболочке в контейнере, введите следующую команду:
docker exec -it 715624b7e22a /bin/bash
Затем вы получите доступ к оболочке для контейнера, и вы можете установить redis:
root@715624b7e22a:/quote-service# apt-get install redis-server
Наконец, запустите root@715624b7e22a:/quote-service# redis-server [25] 29 Nov 00:14:24.546 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 2.8.4 (00000000/0) 64 bit .-`` .-. ```\/ ., ‘’-._ ( ‘ , .-
| ,) Running in stand alone mode | -._- ... - __...-.-._ | ' .- «|
Port: 6379 | -._ .
/ .- '| PID: 25 -._ -. -. / _.- '_.-' | -.- ._ -..- '_.-'_.-' | | -._-._ _.-'_.- '| Http://redis.io -._ -._-.__.-'_.- '_.-' | -._-._ -..- '_.-' .- '| | -._-._.-'.-' | -._ -.- .__.-'_.- '_.-' -. -.__.- '_.-' -._ _.- '`-.__.-'
[25] 29 Nov 00:14:24.547 # Server started, Redis version 2.8.4 [25] 29 Nov 00:14:24.547 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. Чтобы исправить эту проблему добавьте ‘vm.overcommit_memory = 1’ в файл /etc/sysctl.conf а затем перезагрузите систему и выполните команду ‘sysctl vm.overcommit_memory=1’ чтобы изменения вступили в силу. [25] 29 Nov 00:14:24.547 * DB loaded from disk: 0.000 seconds [25] 29 Nov 00:14:24.547 * The server is now ready to accept connections on port 6379 ``` Теперь вы можете просматривать и добавлять цитаты по адресу http://localhost:8000/quotes
.
Размещение приложения (служба цитат) и базы данных (redis) работает на одном сервере. Но, очевидно, это не масштабируется. Войдите в Кубернетес.
Основы Кубернетеса
Кубернетес, a.k.a. K8s, является уместной основой для управления и организации нескольких контейнеров. У этого есть свой собственный способ как делать вещи, которые обычно очень хороши. Он все еще находится в разработке, поэтому иногда могут возникать проблемы. Кубернетес имеет много концепций и очень гибкий. Я объясню и продемонстрирую концепции, применив их к сервису цитат.
Настройка кластера
Существует множество способов создания кластера Kubernetes. Kubernetes может работать на простом сервере, на Google Container, на AWS, и локально на любой ОС с использованием виртуальных машин. Для целей этой статьи я создал кластер из одного мастера и двух миньонов с помощью кластера Core OS OSX GUI k8s. В Mac OS X имеется небольшое меню, в котором вы можете получить доступ ко многим инструментам управления кластерами.
Следуйте инструкциям, и вы быстро все настроите.
Если вы не используете Mac OSX или просто не интересуетесь графическим интерфейсом, вы можете использовать этот проект для настройки тестового кластера в Vagrant VM.
С этого момента я буду использовать командную строку.
Инструмент командной строки kubectl
Kubectl - швейцарский армейский нож Кубернетеса. Вы можете полностью управлять своим кластером с комфортом из своей консоли, используя только kubectl.
Ниже приведен список команд: get Показать один или несколько ресурсов show Показывать детали определенного ресурса create Создайте ресурс по имени файла или stdin update Обновить ресурс по имени файла или stdin. Delete Удалить ресурс по имени файла, stdin, ресурсу и идентификатору, а также по ресурсам и селектору ярлыков. Namespace SUPERCEDED: установить и просмотреть текущий журнал пространства имен Kubernetes. Roll-update Выполнять текущее обновление данного контроллера репликации. Resize Установите новый размер для контроллера репликации. Exec Выполнить команду в контейнере. port-forward Переместить один или несколько локальных портов в контейнер. proxy Запустить прокси-сервер для сервера-загрузчика API-интерфейса Kubernetes Запустить определенный образ в кластере. stop корректно отключить ресурс по имени или имени файла. expose взять реплицированное приложение и опубликовать его в Kubernetes Service. label обновить метки ресурса config Изменяет файлы kubeconfig. cluster-info Отображает информацию о кластере api-versions выводит доступные версии API. version выводит информацию о версии клиента и сервера. help Справка о любой команде
Не стесняйтесь использовать справочную команду или документацию для изучения того, что делает каждая команда. Многие из них используются для выполнения ручных операций, которые лучше выполнять с использованием файлов конфигурации в широкомасштабной масштабируемой распределенной системе, но это может быть необходимо для быстрой разведки и устранения неполадок. Наиболее распространенными командами, которые я буду использовать, являются: get, create, delete и start.
Pods
Пакет является базовой единицей развертывания и управления в Кубернете. Pod представляет собой группу из одного или нескольких контейнеров. Вы можете указать pod, используя выделенный файл YAML или как часть службы Kubernetes (см. ниже). Контейнер всегда развертывается на одном хосте, и все контейнеры внутри pod могут обращаться друг к другу через localhost. Все контейнеры внутри pod всегда запускаются, останавливаются и масштабируются вместе.
Чтобы проверить все pod'ы в кластере, введите:
kubectl get pods
Результатом будет что-то вроде: NAME READY STATUS RESTARTS AGE quote-frontend-4kyns 1/1 Running 0 1h quote-frontend-v4xk1 1/1 Running 0 1h quote-store-controller-y4ya1 1/1 Running 0 23h ### Volumes
Контейнеры не должны поддерживать стойкое состояние. Когда контейнер выходит из строя или перезапускается, его локальная файловая система уничтожается. Если вы хотите сохранить постоянное состояние, вы должны использовать постоянные тома. Поскольку все в Kubernetes основано на pod'ах, вам также нужно определить объемы в pod'е. Вот файл определения pod с постоянным томом: apiVersion: v1 kind: Pod metadata: name: метки-хранилища: app: quote-api role: persistent-storage spec: container: - name: redis image: redis volumeMounts: - Name: quot-store-volume mountPath: / data / redis volume: - name: quote-store-volume emptyDir: {}
Обратите внимание, что постоянные тома ограничены узлом и будут сохранение при выходе контейнера из строя и после его перезапуска, но не после сбоя узла/хоста. Вам все еще необходимо выполнить репликацию и резервное копирование важных данных.
Контроллеры репликации
Одной из важнейших особенностей Kubernetes является его способность управлять и легко масштабировать вверх и вниз количество pod'ов. Как правило, у вас будут разные типы контейнеров в вашей системе, и вы захотите указать, сколько pod'ов каждого типа должно быть запущено.
Поприветствуем контроллеры репликации. Контроллер репликации имеет шаблон pod'а, который определяет группу контейнеров, набор меток для идентификации этих pod'ов и количество желаемых pod'ов. Контроллер репликации гарантирует, что количество запущенных pod'ов, идентифицированных его метками, всегда совпадает с нужным числом. Если pod завершается, контроллер репликации немедленно создаст новый.
Существует несколько интересных вариантов использования, поддерживаемых контроллерами репликации, таких как высокая доступность, эластичное масштабирование и накатывание обновлений. Например, вы можете добавлять и удалять pod'ы из dominion контроллера репликации, изменяя их метку.
Разумеется, контроллеры репликации указаваются в файле YAML. Вот пример: `` `apiVersion: v1 kind: ReplicationController
metadata: name: quote-frontend spec: replicas: 2 # selector identifies the set of Pods that this # replication controller is responsible for managing selector: app: quote-api role: frontend # podTemplate defines the ‘cookie cutter’ used for creating # new pods when necessary template: metadata: labels: # Important: these labels need to match the selector above # The api server enforces this constraint. app: quote-api role: frontend spec: containers: - name: quote-service image: g1g1/quote-service env: - name: GET_HOSTS_FROM # value: dns value: env ports: - containerPort: 8000 ``` Спецификация шаблона для контейнера quote-service используется образ g1g1/quote-service, который я ранее выложил на Docker Hub. Обратите внимание на раздел env
, в котором обмен информацией между контейнерами может происходить через переменные DNS или среды.
Чтобы создать контроллер репликации, введите:
kubectl create -f <имя файла контроллера репликации>
Чтобы просмотреть текущие контроллеры репликации в кластере, введите:
kubectl get rc
Вы должны увидеть что-то вроде: CONTROLLER CONTAINER (S) IMAGE (S) SELECTOR REPLICAS AGE quote-frontend quote-service g1g1 / quote-service app = quote-api, role = frontend 2 1h quote-store-controller master redis app = quote -api, role = persistent-storage 1 1d
### Services
Служба предоставляет свой пакет для остальной части кластера и, доступна извне через переменные среды или DNS. Например, служба цитат состоит из двух типов pod'ов: redis store pod и front-end pod. Фронтенд контейнер должен иметь возможность находить контейнер для хранения, а клиенты должны иметь возможность отправить запрос по одной публичной конечной точке для доступа к службе.
Услуга Kubernetes реализована в еще одном файле YAML. Каждый компонент вашей системы, к которому должны обращаться другие компоненты, должен иметь свой собственный служебный файл. Вот два служебных файла для компонентов сервиса цитат:
srv-quote-frontend.yaml
1 |
apiVersion: v1 |
2 |
kind: Service |
3 |
metadata: |
4 |
name: quote-frontend |
5 |
spec: |
6 |
type: NodePort |
7 |
ports: |
8 |
- port: 8000 # the port that this service should serve on |
9 |
# the container on each pod to connect to, can be a name |
10 |
# (e.g. 'www') or a number (e.g. 80) |
11 |
targetPort: 80 |
12 |
protocol: TCP |
13 |
# just like the selector in the replication controller, |
14 |
# but this time it identifies the set of pods to load balance |
15 |
# traffic to. |
16 |
selector: |
17 |
app: quote-api |
18 |
role: frontend |
#### srv-quote-store.yaml apiVersion: v1 kind: Service metadata: name: quote-store spec: ports: - port: 6379 # the port that this service should serve on targetPort: 6379 # just like the selector in the replication controller, # but this time it identifies the set of pods to load balance # traffic to. selector: app: quote-api role: persistent-storage
Хост и порт каждой службы становятся доступными для каждого контейнера в кластере. Например, если вы запускаете интерактивную оболочку на одном из контейнеров фронтенда:
kubectl quote-frontend-4kyns exec -i -t bash
Затем вы можете проверить, что среда содержит необходимую информацию о хосте и порте для подключения к хранилищу цитат. Root @ quote-frontend-4kyns: / quote-service # env | Grep STORE QUOTE_STORE_PORT_6379_TCP_ADDR = 10.100.234.192 QUOTE_STORE_PORT_6379_TCP_PROTO = ТСР QUOTE_STORE_SERVICE_PORT = 6379 QUOTE_STORE_PORT_6379_TCP_PORT = 6379 QUOTE_STORE_PORT = ТСР: //10.100.234.192: 6379 QUOTE_STORE_PORT_6379_TCP = ТСР: //10.100.234.192: 6379 QUOTE_STORE_SERVICE_HOST = 10.100.234.192
Просто, чтобы освежить вашу память, Это именно то, что делает frontend: redis_host = os.environ.get ('QUOTE_STORE_SERVICE_HOST', 'localhost') redis_server = redis.StrictRedis (host = redis_host, port = 6379, db = 0)
## Заключение
Докер и Кубернетес - захватывающие технологии. Эта статья едва поцарапала поверхность того, что возможно. Преимущества огромны, но инфраструктура, инструменты и лучшие практики все еще развиваются. Если вы даже дистанционно подключены к крупномасштабным распределенным системам, я рекомендую вам по крайней мере оставаться на вершине этих технологий и в идеале окунуться в них и попытаться их использовать. Существует множество способов экспериментировать и учиться без массово миграции всей вашей производственной инфраструктуры.
Что касается Кубернетеса, есть несколько других альтернатив для управления несколькими контейнерами и оркестровки, такие как Mesos и Docker compose. Я считаю, что Кубернетес более архитектурно обоснован, имеет большой импульс и лучше, чем остальные его альтернативы.