Админим с Буквой
5.52K subscribers
303 photos
8 videos
59 files
1.16K links
Канал о системном администрировании, DevOps и немного Инфобеза.

По всем вопросам обращаться к @bykva. Рекламу не размещаю.
Download Telegram
uwsgi && docker

Замечательный софт, без сомнения.

Проблемы запуска uwsgi в docker ровно две - и обе они кроются в init скриптах автора.

1) /etc/init.d/uwsgi start вываливается с ошибкой. вот просто так, из коробки, сразу. Погружаемся в исходники и начинаем искать проблему. Она кроется в выполнении этой команды:
start-stop-daemon --start --quiet \
--pidfile "$PIDFILE" \
--exec "$DAEMON" \
--test > /dev/null \
&& return 2

До этого этапа все выполняется прекрасно, процессы стартуют и главное начинают работать даже после выпадения с ошибкой init-скрипта. Проблема кроется в том, что внутри докера нет прав на прочтение /proc/{id}/exe. После чего считается что процесса нет и согласно заложенному поведению выдается код возврата 0, отсюда выдается код возврата 2 (return 2), который и дает в результате ошибку запуска. Обсуждение этого косяка при запуске разного ПО идет аж с 14 года: https://github.com/moby/moby/issues/6800.
Workaround:
a) исправляем в файле /usr/share/uwsgi/init/specific_daemon в приведенном мною выше коде ключ --exec на --startas. Согласно ману (да нет, шутка, согласно ману они одинаково работают, так что согласно форумам) при использовании ключа startas будет пропущена проверка /proc/{id}/exe и просто проверяется запущен ли процесс с таким pid. (https://chris-lamb.co.uk/posts/start-stop-daemon-exec-vs-startas)
b) запуск контейнера с ключем --cap-add=SYS_PTRACE. В этом случае править ничего не нужно.
с) не использовать авторские init-скрипты и запускать напрямую

2) После запуска /etc/init.d/uwsgi start скрипт прекрасно отрабатывает и выходит. Докер естественно после этого завершается. Причем демонизация захардкожена автором в скрипте запуска, без возможности указать в конфиге хочешь ты этого или нет. На этом моменте я все же психанул и сначала поправил скрипт запуска, но потом понял что все же это не тру путь и нужно от этого отказываться, делая просто одну строчку запуска и один конфиг файл.

В итоге что было сделано:
1) в конфиг добавлены следующие параметры (и остальные из дефолтного конфига):
...

stats = 0.0.0.0:9090
socket = 0.0.0.0:3031
pidfile = /run/uwsgi/pid
socket = /run/uwsgi/socket
...


2) в Dockerfile:

...

COPY app.ini /etc/uwsgi/apps-enabled/app.ini
RUN mkdir /run/uwsgi && chown www-data /run/uwsgi

CMD ["/usr/bin/uwsgi", "--ini", "/etc/uwsgi/apps-enabled/app.ini"]


таким образом мы избавились и от той левой проверки из п.1 и от ключа демонизации из п.2, и сами выставили права и место pid\socket.

#troubleshooting #docker #uwsgi
Используем systemd для запуска docker-контейнеров

[Unit]
Description=My Awesome Service
Requires=docker.service
After=docker.service

[Service]
Restart=always
RestartSec=3
ExecStartPre=/bin/sh -c "/usr/bin/docker rm -f my-awesome-service 2> /dev/null || /bin/true"
ExecStart=/usr/bin/docker run --rm -a STDIN -a STDOUT -a STDERR --env-file=/etc/default/my-awesome-service -p 0.0.0.0:3301:3301 -v /etc/project/service:/etc/wallarm -v /var/lib/blacklist:/var/lib/blacklist -v /var/log/project/service:/var/log/wallarm --name my-awesome-service wallarm-dkr.jfrog.io/my-awesome-service:v0.17.0.0
ExecStop=/usr/bin/docker stop my-awesome-service

[Install]
WantedBy=multi-user.target


#systemd #docker
Билдим собственный однобинарный образ на примере hello-world

все примеры взяты с гитхабчика докера и изменены в пользу упрощения.

Для задачи будет использоваться слой scratch, который представляет из себя слой без какой-либо начинки. Использование образа scratch сигнализирует билд-процессу, что следующая команда в Dockerfile будет вашим первым слоем в образе. Таким образом мы получаем контейнер, состоящий как бы из одного вашего бинаря.

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

1) Возьмем С-код, которые выведет на экран слова приветствия

#include <unistd.h>
#include <sys/syscall.h>

const char message[] =
"\n"
"hello world\n"
"\n";

void main() {
//write(1, message, sizeof(message) - 1);
syscall(SYS_write, 1, message, sizeof(message) - 1);

//_exit(0);
syscall(SYS_exit, 0);
}


2) сбилдим:

gcc hello.c -o hello -static


3) Dockerfile:

FROM scratch
COPY hello /
CMD ["/hello"]


4) билдим образ:

docker build -t hello ./


5) проверяем:

docker run hello


и ответ:

hello world


Сравнение

если запросить du -hs hello и посмотреть docker images hello их разница будет всего в пару десятков КБ. (792K -> 810К в моем случае)

Благодарности Михаилу за помощь с Си =)
#docker #hello_world
Docker pull via proxy

# systemctl edit docker.service


add the following strings:

[Service]
Environment=ALL_PROXY=socks5://user:password@host:port


reload systemd && restart docker

# systemctl daemon-reload
# systemctl restart docker.service


#proxy #docker
Список тегов, используемых в канале:

—-------------------------------
Лекции и материалы
—-------------------------------
#Занятие
#Лекции
Лекция
#junior

—---------
Linux
—---------
#ssh
#bash
#bash_tips_and_tricks
#awk
#tmux
#console
#utils
#troubleshooting
#nmap
#apt
#bind
#sound
#power_management

—----------
DevOps
—----------
#jenkins
#ansible
#git
#kubernetes
#deploy
#ceph
#docker
#puppet

—------------------
Virtualization
—------------------
#vmware
vagrant

—------------------
Networking
—---------------—
#networking
#proxy
#socks

—---------
InfoSec
—---------
#vulns
#security
#ctf

—-------------
Windows
—-------------
#RDTS
#windows_server2012
#RDP

—------------
Datacenters
—---------—
#ovh
#hetzner

—-------
Other
—-------
#android
#jira

—------------------------------------------------
Ссылки и сторонние материалы
—------------------------------------------------
#read
#thirdparty

Updated: 29.05.18
Docker up to date checking

Сервис для проверки ваших докер контейнеров на "обновленность". Для публичных - бесплатно. приватные - за денежку.

https://anchore.io/

#docker
Убитый контейнер докера не запускается

Ошибка:
endpoint with name XXXX already exists in network bridge.
Решение:
docker network disconnect --force bridge <Container ID or Endpoint ID or Container NAME>

Это не для тех, кто не умеет гуглить, а для того чтобы наоборот каждый раз не гуглить когда такое возникает=)

#docker #troubleshooting #networking
Запускаем задачу в background в докер контейнере через ansible

Особо ничего сложного, nohup да &, однако процесс все равно не отпускает консоль, посему ansible зависает. Чтобы этого не происходило, можно применить такую конструкцию:

- name: run bg job
shell: docker exec -i <container> sh -c 'nohup CMD &'
async: 45
poll: 0

#docker #ansible
RBAC on docker registry

Поигрался тут на днях с одним сервисом который позволяет использвать token-based аутентификацию пользователя с docker registry. Стандартный вариант логин-пароль уже не удовлетворяет потребностям и пришлось искать что-то другое. В итоге набрел на готовое решение от cesanta/docker_auth. Написано на go, легковестный token-сервис с поддержкой различных способов аутентификации пользователей и также, что самое главное - это ACL. С помощью acl можно задавать кто, и какие репозитории может пушить и пуллить, с точностью до регулярного выражения. В качестве базы хранения пользователей-acl можно выбрать статический файл, mongodb, ldap и некоторые другие. В том числе можно использовать и сторонний софт, хоть самопис. токен будет выдаваться в зависимости от кода ответа этого софта. И тут уже можно сделать все что угодно - хоть выдавать токены в зависимости от времени суток. Поковырявшись в этом собрал готовое решение, запускаемое через docker-compose. Оно содержит набор из 3 контейнеров: docker_auth, docker registry и mongo. После старта docker-compose все что нужно сделать - загрузить список правил и пользователей в mongo через простейший shell-скрипт.

https://github.com/bykvaadm/docker_auth

#docker #auth
Cleanup docker registry

Проверено для версии 2.6.2

1. добавить в конфиг registry эти строки и перезапустить:

storage:
delete:
enabled: true


2. получаем список тегов для репозитория и выбираем список на удаление

curl -u <user>:<password> https://<registry_host>/v2/<repo_name>/tags/list


3. помечаем объекты на удаление через api

repo="REPO_PATH"
tag_list='TAG LIST separated by space'
user="USER"
pwd="PASSWORD"
registry_host="<registry_host>"
header="Accept: application/vnd.docker.distribution.manifest.v2+json"

for tag in ${tag_list}; do
digest=$(curl -I -u $user:$pwd -H "$header" "https://${registry_host}/v2/${repo}/manifests/${tag}" 2>/dev/null| awk '$1 == "docker-content-digest:" {print $2}'| tr -dc '[[:print:]]')
curl -XDELETE -u $user:$pwd -H "$header" "https://${registry_host}/v2/${repo}/manifests/${digest}"
done


4. заходим внутрь контейнера и запускаем garbage-collector.

registry garbage-collect /etc/docker/registry/config.yml


Итого наша задача - получить список тегов, выбрать нужные на удаление. На каждый тег получить sha256 манифеста (docker-content-digest в заголовке ответа), а затем пометить этот заголовок на удаление. К концу 3-го пункта никакие данные еще не удалены. Удаление происходит не вручную, а с помощью нативного сборщика мусора. согласно помеченным манифестам будут удалены выбранные теги.

#docker #registry
Интегрируем проверку на уязвимости в CI

The Anchore Engine is an open source project that provides a centralized service for inspection, analysis and certification of container images. 

https://github.com/anchore/anchore-engine

https://medium.com/devopslinks/step-by-step-guide-to-integrate-opensource-container-security-scanner-anchore-engine-with-cicd-580da8db5dfc

#docker #jenkins #security