- PVSM.RU - https://www.pvsm.ru -
Недавно мы добавили в сервис «Виртуальное приватное облако» [1] новый образ с операционной системой RancherOS [2] и обновили образ CoreOS [3].
Эти операционные системы будут интересны пользователям, которым необходим инструмент для простого управления большим количеством приложений в контейнерах и использования различных систем кластеризации контейнеров — Kubernetes [4], Docker Swarm [5], Apache Mesos [6] и других.
CoreOS и RancherOS отличаются от большинства популярных дистрибутивов Linux: они содержат лишь минимальный набор программного обеспечения для запуска приложений внутри контейнеров. В этих системах отсутствуют пакетные менеджеры и интерпретаторы различных языков программирования (Python, Ruby и других.).
Ниже мы рассмотрим специфику CoreOS и RancherOS, разберём особенности конфигурации сервисов etcd и fleet, а также приведём пример настройки кластера Docker Swarm на базе RancherOS.
Дистрибутив CoreOS [3] разработан специально для быстрого и массового развертывания большого количества пользовательских приложений в изолированных контейнерах.
CoreOS содержит предустановленные инструменты для удобного управления множеством нод и контейнеров в кластере:
Основной метод изменения системных параметров ― это описание необходимых настроек при помощи декларативного языка YAML [12] в конфигурационном файле cloud-config.yml. Этот файл используется утилитой Cloud-init [13] для настройки системы.
Обратите внимание, что в CoreOS используется собственная реализация Cloud-init, конфигурационные файлы которой лишь частично совместимы с настройками для более распространенной версии Launchpad-cloud-init [14], используемой в большинстве обычных дистрибутивов для конфигурации системы в различных облачных сервисах, в том числе и в сервисе «Виртуальное приватное облако».
Приведем пример файла cloud-config.yml:
#cloud-config
# Set hostname
hostname: "node01"
# Set ntp servers
write_files:
- path: /etc/systemd/timesyncd.conf
content: |
[Time]
NTP=0.ru.pool.ntp.org 1.ru.pool.ntp.org
coreos:
units:
# Configure static network on eth0 interface
- name: iface-eth0.network
runtime: true
content: |
[Match]
Name=eth0
[Network]
DNS=188.93.16.19
DNS=188.93.17.19
DNS=109.234.159.91
Address=10.11.12.13/24
Gateway=10.11.12.1
# Change standard SSH port
- name: sshd.socket
command: restart
runtime: true
content: |
[Socket]
ListenStream=2345
FreeBind=true
Accept=yes
При помощи заданных параметров утилита Cloud-init сменит хостнейм и стандартный порт 22 для сервиса SSH, настроит статическую сеть на интерфейсе eth0 и добавит ntp-серверы для синхронизации времени.
Подробнее о структуре конфигурационного файла cloud-config.yml можно прочитать в официальной документации [15].
При создании сервера из готового образа CoreOS в сервисе «Виртуальное приватное облако» вам не потребуется производить базовую настройку системы при помощи cloud-config.yml. Мы уже внесли необходимые изменения в образ, при помощи которых автоматически производится стандартная конфигурация сервера, в том числе настройка сетевых интерфейсов.
Доступ по SSH к серверу под управлением CoreOS изначально будет возможен только по ключу, указанному при создании сервера. Указанный ключ будет добавлен для пользователя core.
В дополнение к собственной версии cloud-init создатели CoreOS разработали утилиту Ignition [16]. Этот инструмент дублирует возможности cloud-init и еще позволяет производить низкоуровневые настройки системы, — например, изменение таблиц разделов дисков и форматирование файловых систем. Это возможно благодаря тому, что Ignition начинает работать во время ранних этапов загрузки системы, в процессе запуска initramfs [17].
В Ignition для конфигурационных файлов используется формат JSON [18].
Ниже представлен пример файла, при помощи которого Ignition отформатирует корневой раздел в Btrfs [19], и настроит систему с параметрами, аналогичными примеру выше для Cloud-init:
{
"ignition": { "version": "2.0.0" },
"storage": {
"filesystems": [{
"mount": {
"device": "/dev/disk/by-label/ROOT",
"format": "btrfs",
"create": {
"force": true,
"options": [ "--label=ROOT" ]
}
}
}],
"files": [{
"filesystem": "root",
"path": "/etc/systemd/timesyncd.conf",
"mode": 420,
"contents": { "source": "data:,%5BTime%5D%0ANTP=0.ru.pool.ntp.org%201.ru.pool.ntp.org%0A" }
},
{
"filesystem": "root",
"path": "/etc/hostname",
"mode": 420,
"contents": { "source": "data:,node01" }
}
]
},
"networkd": {
"units": [{
"name": "iface-eth0.network",
"contents": "[Match]nName=eth0nn[Network]nDNS=188.93.16.19nDNS=188.93.17.19nDNS=109.234.159.91nAddress=10.11.12.13/24nGateway=10.11.12.1"
}]
},
"systemd": {
"units": [{
"name": "sshd.socket",
"command": "restart",
"runtime": true,
"contents": "[Socket]nListenStream=2345nFreeBind=truenAccept=yes"
}]
}
}
Подробнее о всех возможностях Ignition можно узнать в официальной документации [20].
Для этого примера нам потребуется заранее создать три сервера под управлением CoreOS в панели управления VPC [21] со следующими параметрами:
После создания серверов потребуется discovery-url [22] для сервиса etcd. Для этого мы можем воспользоваться публичным бесплатным сервисом discovery.etcd.io [23]. Запустим на хосте node00 следующую команду:
core@node00 ~ $ curl -w "n" 'https://discovery.etcd.io/new?size=3'
https://discovery.etcd.io/ec42cfef0450bd8a99090ee3d3294493
Добавим полученный URL и дополнительные параметры etcd в файл /usr/share/oem/cloud-config.yml на каждом сервере:
coreos:
etcd2:
discovery: https://discovery.etcd.io/ec42cfef0450bd8a99090ee3d3294493
advertise-client-urls: http://192.168.0.10:2379,http://192.168.0.10:4001
initial-advertise-peer-urls: http://192.168.0.10:2380
listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001
listen-peer-urls: http://192.168.0.10:2380
units:
- name: etcd2.service
command: start
- name: fleet.service
command: start
Параметры в разделе etcd2 обозначают URL-адреса в формате protocol://address:port, которые необходимы для анонсирования ноды и обмена данными с другими членами кластера.
Раздел units позволяет управлять юнитами systemd в системе; в нашем случае он запустит юниты etc2d.service и fleet.service.
Для серверов node01 и node02 вам будет необходимо добавить аналогичные изменения в cloud-config.yml, изменив ip-адрес с 192.168.0.10 на 192.168.0.11 для сервера node01, и на адрес 192.168.0.12 для сервера node02.
После добавления новых настроек запустим утилиту Cloud-init на всех трех серверах (либо можно просто перезапустить эти серверы):
core@node00 ~ $ sudo coreos-cloudinit --from-file /usr/share/oem/cloud-config.yml
Также проверим статус сервиса etcd:
core@node00 ~ $ etcdctl cluster-health
member 3aaf91fd1172594e is healthy: got healthy result from http://192.168.0.11:2379
member 8cf40790248e1dcd is healthy: got healthy result from http://192.168.0.12:2379
member 96b61f40c082cd0b is healthy: got healthy result from http://192.168.0.10:2379
cluster is healthy
Проверим доступность распределенного хранилища, добавим новую директорию (в терминологии etcd — ключ) со значением на сервере node00:
core@node00 ~ $ etcdctl set /common/cluster-name selectel-test-cluster
selectel-test-cluster
Затем убедимся, что наш новый ключ со значением доступен с любой другой ноды кластера:
core@node01 ~ $ etcdctl get common/cluster-name
selectel-test-cluster
Отлично, etcd функционирует, и мы можем приступать к использованию сервиса fleet.
В нашем примере мы будем использовать fleet для запуска Nginx в изолированном контейнере Docker. Для начала создадим systemd-юнит /etc/systemd/system/nginx.service:
[Unit]
Description=Nginx Test Service
[Service]
EnvironmentFile=/etc/environment
ExecStartPre=/usr/bin/docker pull nginx
ExecStart=/usr/bin/docker run --rm --name nginx -p 80:80 nginx
ExecStop=/usr/bin/docker kill nginx
[X-Fleet]
Conflicts=nginx.service
Параметр Conflicts в секции X-Fleet запрещает запускать два и более сервиса Nginx на одной ноде, что позволит «размазать» нагрузку на кластер и повысить доступность сервиса. Дополнительные параметры X-Fleet, которые можно использовать внутри юнитов systemd описаны в документации fleet [24].
Остальные секции в файле являются стандартными для systemd, вы можете ознакомиться с ними например в небольшой вводной инструкции [25] от CoreOS.
Запустим новый юнит nginx.service в нашем кластере при помощи fleetctl:
core@node00 ~ $ fleetctl start /etc/systemd/system/nginx.service
Unit nginx.service inactive
Unit nginx.service launched on 1ad018e0.../192.168.0.11
После этого мы можем увидеть наличие Nginx в списке юнитов на любой ноде кластера:
core@node02 ~ $ fleetctl list-units
UNIT MACHINE ACTIVE SUB
nginx.service 1ad018e0.../192.168.0.11 active running
core@node02 ~ $ fleetctl list-unit-files
UNIT HASH DSTATE STATE TARGET
nginx.service 0c112c1 launched launched 1ad018e0.../192.168.0.11
Как мы видим, контейнер с Nginx запустился на сервере с ip-адресом 192.168.0.11, которому соответствует сервер node01.
Мы можем отключить или полностью удалить сервер node01, после чего fleet автоматически перенесет Nginx на другую доступную ноду.
Etcd сообщит о недоступности члена при проверке статуса кластера:
core@node00 ~ $ etcdctl cluster-health
failed to check the health of member 3aaf91fd1172594e on http://192.168.0.11:2379: Get http://192.168.0.11:2379/health: dial tcp 192.168.0.11:2379: i/o timeout
failed to check the health of member 3aaf91fd1172594e on http://192.168.0.11:4001: Get http://192.168.0.11:4001/health: dial tcp 192.168.0.11:4001: i/o timeout
member 3aaf91fd1172594e is unreachable: [http://192.168.0.11:2379 http://192.168.0.11:4001] are all unreachable
member 8cf40790248e1dcd is healthy: got healthy result from http://192.168.0.12:2379
member 96b61f40c082cd0b is healthy: got healthy result from http://192.168.0.10:2379
cluster is healthy
Но как мы видим, статус сервиса Nginx в норме, он запустился на другой рабочей ноде:
core@node00 ~ $ fleetctl list-units
UNIT MACHINE ACTIVE SUB
nginx.service 4a1ff11c.../192.168.0.10 active running
Мы разобрали элементарный пример конфигурации кластера etcd + Docker + fleet на базе CoreOS. В следующем разделе мы рассмотрим другой дистрибутив — RancherOS, который основан на CoreOS и также предназначен для активного использования контейнеров.
Дистрибутив RancherOS представляет собой форк CoreOS. Отличительная особенность этой системы заключается в том, что в контейнерах запускаются не только пользовательские приложения, но и все системные сервисы. Более того, в RancherOS Docker имеет PID = 1, поэтому запускается сразу после ядра системы.
Операционная система содержит два Docker-инстанса; один из них является системным, в нём запускаются контейнеры udev, acpid, syslog, ntp и другие базовые сервисы, необходимые для работы системы. Системный Docker-инстанс заменяет собой традиционные системы инициализации (systemd, Upstart, SysV), присутствующих в обычных дистрибутивах Linux.
Второй Docker-инстанс используется для запуска пользовательских приложений и представляет собой специальный контейнер, запущенный внутри системного Docker’а.
Такое разделение обеспечивает защиту системных контейнеров от некорректных действий пользователя.
Так как Docker-инстанс в RancherOS представляет собой обычное Docker-окружение, то мы можем использовать стандартный набор команд [26] Docker для управления как пользовательскими так и системными контейнерами.
# проверка версии Docker
[rancher@rancher-os ~]$ docker --version
Docker version 1.12.1, build 23cf638
# установка нового контейнера из Docker Hub
[rancher@rancher-os ~]$ docker run -d nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
…
Status: Downloaded newer image for nginx:latest
# просмотр списка запущенных контейнеров
[rancher@rancher-os ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2ec5126e8dd5 nginx "nginx -g 'daemon off" About a minute ago Up About a minute 80/tcp, 443/tcp sad_fermat
Для доступа к системным контейнерам необходимо использовать команду system-docker вместе с утилитой sudo [27].
Просмотреть список запущенных базовых сервисов операционной системы можно с помощью команды:
[rancher@rancher-os ~]$ sudo system-docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a566d0c7cc4c rancher/os-docker:1.12.1 "/usr/bin/user-docker" 8 minutes ago Up 8 minutes docker
8697a04e90a4 rancher/os-console:v0.6.1 "/usr/bin/ros entrypo" 8 minutes ago Up 8 minutes console
c8c337282aaa rancher/os-base:v0.6.1 "/usr/bin/ros entrypo" 8 minutes ago Up 8 minutes network
1e55244fc99c rancher/os-base:v0.6.1 "/usr/bin/ros entrypo" 8 minutes ago Up 8 minutes ntp
fd6a03fdb28f rancher/os-udev:v0.6.1 "/usr/bin/ros entrypo" 8 minutes ago Up 8 minutes udev
7e9e50c28651 rancher/os-acpid:v0.6.1 "/usr/bin/ros entrypo" 8 minutes ago Up 8 minutes acpid
5fec48b060f2 rancher/os-syslog:v0.6.1 "/usr/bin/ros entrypo" 8 minutes ago Up 8 minutes syslog
Перезапуск системного контейнера осуществляется так:
[rancher@rancher-os ~]$ sudo system-docker restart ntp
Основным инструментом автоматической конфигурации системы является собственная имплементация cloud-init, который был разделен на две отдельные утилиты: cloud-init-execute [28] и cloud-init-save [29]. По аналогии с другими реализациями cloud-init, версия RancherOS использует декларативный язык YAML, однако cloud-config.yml для другого дистрибутива не будет совместим с RancherOS.
Все возможные директивы конфигурационного файла описаны в официальной документации docs.rancher.com/os [30].
Системные сервисы используют параметры, полученные из файлов, в описанной ниже последовательности (каждый последующий файл из указанного списка перезаписывает предыдущие параметры, если они совпадают):
Вы можете изменять конфигурацию системы при при помощи утилиты ros, после чего новые параметры будут отображаться в файле /var/lib/rancher/conf/cloud-config.yml:
[rancher@rancher-os ~]$ sudo ros config set rancher.network.dns.nameservers "['188.93.16.19','188.93.17.19', '109.234.159.91']"
[rancher@rancher-os ~]$ sudo cat /var/lib/rancher/conf/cloud-config.yml
rancher:
network:
dns:
nameservers:
- 188.93.16.19
- 188.93.17.19
- 109.234.159.91
Помимо изменения конфигурации системных сервисов утилита ros также используется для управления версиями операционной системы, версиями Docker, настройкой TLS и SELinux.
При использовании готового образа RancherOS в сервисе «Виртуальное приватное облако» вам нет необходимости настраивать базовые параметры системы (конфигурацию сетевых интерфейсов и т.п.)
После установки сервер будет доступен по выбранному вами IP-адресу в панели управления VPC. Вы сможете подключиться к серверу, используя протокол SSH, однако аутентификация изначально будет возможна только по ключу, указанному при создании сервера. Этот ключ будет добавлен для пользователя rancher.
Чтобы узнать текущую версию операционной системы, используйте команду:
[rancher@rancher-os ~]$ sudo ros os version
v0.6.1
А для проверки всех доступных релизов:
[rancher@rancher-os ~]$ sudo ros os list
rancher/os:v0.4.0 remote
rancher/os:v0.4.1 remote
rancher/os:v0.4.2 remote
rancher/os:v0.4.3 remote
rancher/os:v0.4.4 remote
rancher/os:v0.4.5 remote
rancher/os:v0.5.0 remote
rancher/os:v0.6.0 remote
rancher/os:v0.6.1 remote
Вы можете установить последнюю стабильную версию системы при помощи команды sudo ros os upgrade, либо выбрать требуемую версию, указав параметр -i:
[rancher@rancher-os ~]$ sudo ros os upgrade -i rancher/os:v0.5.0
Так как указанная нами версия 0.5.0 старше, чем установленная 0.6.1, то вместо обновления системы произойдет даунгрейд
Управлять версией Docker не менее просто. Приведём несколько примеров:
#просмотр доступных версий
[rancher@rancher-os ~]$ sudo ros engine list
disabled docker-1.10.3
disabled docker-1.11.2
current docker-1.12.1
#установка версии 1.11.2
[rancher@rancher-os ~]$ sudo ros engine switch docker-1.11.2
INFO[0000] Project [os]: Starting project
INFO[0000] [0/19] [docker]: Starting
…
INFO[0010] Recreating docker
INFO[0010] [1/19] [docker]: Started
В Docker 1.12 появились интегрированные инструменты для управления кластером контейнеров Docker Swarm, благодаря чему настроить готовый кластер стало гораздо проще.
В нашем примере мы будем использовать готовый образ RancherOS в сервисе «Виртуальное приватное облако». В нём используется Docker версии 1.12.1.
Нам понадобится создать три сервера со следующими параметрами:
Для начала нам необходимо инициализировать создание кластера Docker Swarm, для этого на ноде manager0 выполним следующую команду:
[rancher@manager0 ~]$ docker swarm init --advertise-addr 192.168.0.100
Swarm initialized: current node (8gf95qb6l61v5s6561qx5vfy6) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join
--token SWMTKN-1-0hlhela57gsvxzoaqol70n2b9wos6qlu3ukriry3pcxyb9j2k6-0n1if4hkvdvmrpbb7f3clx1yg
192.168.0.100:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
Как вы можете заметить из появившейся подсказки, на нодах worker0 и worker1 вам необходимо выполнить команду:
docker swarm join
--token SWMTKN-1-0hlhela57gsvxzoaqol70n2b9wos6qlu3ukriry3pcxyb9j2k6-0n1if4hkvdvmrpbb7f3clx1yg
192.168.0.100:2377
Проверим статус нод кластера, для этого на manager0 запустим команду:
[rancher@manager0 ~]$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
366euocei01dw3ay66uwzb3pv worker0 Ready Active
67pt4fo5gi13cxkphtfzfbfbo worker1 Ready Active
8gf95qb6l61v5s6561qx5vfy6 * manager0 Ready Active Leader
Docker Swarm готов к использованию!
По умолчанию новые сервисы будут запускаться на всех нодах кластера. Подкорректируем данные настройки таким образом, чтобы все сервисы запускались на нодах worker0 и worker1, а нода manager0 выполняла только управляющую роль.
Для внесения этих параметров изменим «доступность» ноды manager0:
[rancher@manager0 ~]$ docker node update --availability drain manager0
Запустим сервис с контейнером Nginx:
[rancher@manager0 ~]$ docker service create --name webserver --replicas 1 --publish 80:80 nginx
В ответ мы получим идентификатор сервиса:
av1qvj32mz8vwkwihf0lauiz8
Изначально количество реплик будет равно 0, а единственная задача, относящаяся к этому сервису, будет находится в статусе «Preparing»:
[rancher@manager0 ~]$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
av1qvj32mz8v webserver 0/1 nginx
[rancher@manager0 ~]$ docker service ps webserver
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
cjxkza3qzx5m73bgbls0r26m6 webserver.1 nginx worker1 Running Preparing about a minute ago
Через несколько секунд необходимый образ Nginx будет автоматически скачан из Docker Hub, после чего статус сервиса изменится на «Running»:
[rancher@manager0 ~]$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
av1qvj32mz8v webserver 1/1 nginx
[rancher@manager0 ~]$ docker service ps webserver
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
cjxkza3qzx5m73bgbls0r26m6 webserver.1 nginx worker1 Running Running 8 minutes ago
Как мы видим, сервис запустился на ноде worker1 (значение в столбце «NODE»). Отключим эту ноду через панель управления VPC и снова проверим статус сервиса webserver:
[rancher@manager0 ~]$ docker service ps webserver
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
5lwf4z54p74qtoopuilshw204 webserver.1 nginx worker0 Running Preparing 32 seconds ago
cjxkza3qzx5m73bgbls0r26m6 _ webserver.1 nginx worker1 Shutdown Running 16 minutes ago
Статус сервиса изменился на «Preparing», Docker Swarm пытается перенести сервис на другую рабочую ноду worker0, задержка связана с тем, что перед запуском на ноду worker0 должен быть добавлен образ Nginx из Docker Hub.
После автоматического добавления образа сервис webserver успешно запустится на ноде worker0:
[rancher@manager0 ~]$ docker service ps webserver
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
5lwf4z54p74qtoopuilshw204 webserver.1 nginx worker0 Running Running about a minute ago
cjxkza3qzx5m73bgbls0r26m6 _ webserver.1 nginx worker1 Shutdown Running 19 minutes ago
Чтобы избежать простоя при переносе сервиса с упавшей ноды, мы можем увеличить количество реплик этого сервиса.
Выполним команду (не забудьте включить ноду worker1 обратно):
[rancher@manager0 ~]$ docker service update --replicas 2 webserver
Сервис начнет реплицироваться на вторую ноду worker1:
[rancher@manager0 ~]$ docker service ps webserver
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
5lwf4z54p74qtoopuilshw204 webserver.1 nginx worker0 Running Running 11 minutes ago
cjxkza3qzx5m73bgbls0r26m6 _ webserver.1 nginx worker1 Shutdown Complete 6 minutes ago
f3o7icke69zw83ag92ywol0dr webserver.2 nginx worker1 Running Preparing 2 seconds ago
В этой статье мы проделали обзор дистрибутивов Linux, предназначенных для быстрого развертывания и удобного управления кластером из изолированных контейнеров.
Будем рады, если вы поделитесь собственным опытом использования CoreOS, RancherOS и подобных им операционных систем.
Автор: Селектел
Источник [31]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/linux/212923
Ссылки в тексте:
[1] «Виртуальное приватное облако»: https://selectel.ru/services/vpc/
[2] RancherOS: http://rancher.com/rancher-os/
[3] CoreOS: https://coreos.com/
[4] Kubernetes: http://kubernetes.io/
[5] Docker Swarm: https://docker.github.io/swarm/overview/
[6] Apache Mesos: http://mesos.apache.org/
[7] etcd: https://coreos.com/etcd/
[8] Docker: https://www.docker.com/
[9] rkt: https://coreos.com/rkt/
[10] fleet: https://coreos.com/fleet/
[11] systemd: https://www.freedesktop.org/wiki/Software/systemd/
[12] YAML: http://yaml.org/
[13] Cloud-init: https://github.com/coreos/coreos-cloudinit
[14] Launchpad-cloud-init: https://launchpad.net/cloud-init
[15] официальной документации: https://coreos.com/os/docs/latest/
[16] Ignition: https://coreos.com/blog/introducing-ignition.html
[17] initramfs: https://en.wikipedia.org/wiki/Initramfs
[18] JSON: http://www.json.org/
[19] Btrfs: https://btrfs.wiki.kernel.org/index.php/Main_Page
[20] официальной документации: https://coreos.com/ignition/docs/latest/
[21] панели управления VPC: https://support.selectel.ru/vpc/projects/
[22] discovery-url: https://coreos.com/etcd/docs/latest/discovery_protocol.html
[23] discovery.etcd.io: https://discovery.etcd.io/
[24] документации fleet: https://coreos.com/fleet/docs/latest/unit-files-and-scheduling.html
[25] инструкции: https://coreos.com/docs/launching-containers/launching/getting-started-with-systemd/
[26] стандартный набор команд: https://docs.docker.com/engine/reference/commandline/
[27] sudo: https://www.sudo.ws/
[28] cloud-init-execute: https://github.com/rancher/os/tree/master/cmd/cloudinitexecute
[29] cloud-init-save: https://github.com/rancher/os/tree/master/cmd/cloudinitsave
[30] docs.rancher.com/os: http://docs.rancher.com/os
[31] Источник: https://habrahabr.ru/post/315930/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.