Админим с Буквой
5.51K subscribers
302 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
Нападение без объявления войны

я хз че это было, но вы поймете когда вам это понадобится))

https://github.com/moby/moby/blob/master/contrib/init/systemd/docker.socket

(Ну а так, ошибка такая: docker.service: Failed to schedule restart job: Unit docker.socket not found.)

#docker #troubleshooting
куда можно потратить 3 часа

Способов потерять время - сотни. Можно поваляться на траве в погожий денек, написать какой-нибудь прикольной зеленоглазой девчонке, а можно... собирать пакеты и тестировать их в докере. И убить эти 3 часа в попытке исполнить .examples/.docs скрипты установки. Ну это те, которые приносят файлики в /usr/share/docs/<package>. Вы кладете туда файл, а он не приезжает после установки пакета. Самое главное что если пакет вскрыть с помощью ar, то нужные файлы там есть. При установке пакета - в нужных местах не появляются. Самое бесячее, что в нужной папке появляется файл copyright, а твои другие - нет.

Ларчик-то просто открывался. Всего-навсего в докере из коробки лежит конфиг dpkg, который говорит, мол copyright клади, а другие файлы не клади...

#packaging #docker
докер в кроне

если вы набили руку вызывать докер через docker exec -ti, и особенно та часть которая относится к -ti, помните, никакого tty в кроне нет и работать это не будет. Поэтому просто, docker exec <ID/NAME> <CMD>.

Сам уже не первый раз натыкаюсь, надоело уже, решил записать))

#docker #cron
Интересное наблюдение

На одном из серверов выполнил вот такую команду:

# ps aux | grep nginx
puppet 6754 ... nginx: worker process
puppet 6755 ... nginx: worker process


Вы наверное тоже насторожились как и я, какого хрена nginx запущен от папета. Оказалось все довольно просто. На сервере nginx запущен в докере:

# docker exec -ti 4da030b0cfb5 ps aux | grep nginx
nginx 668 nginx: worker process
nginx 669 nginx: worker process


А вот ответ на вопрос как так получилось:

# grep puppet /etc/passwd                                                                                                                                              
puppet:x:105:109:Puppet configuration ....
# docker exec -ti 4da030b0cfb5 grep nginx /etc/passwd
nginx:x:105:111:nginx user


#docker
ansible base64 multiply vars

{
"auths": {
"{{ dkr_url }}": {
"auth": "{{ (dkr_user+':'+dkr_password) | b64encode }}"
},
"{{ dkr_dev_url }}": {
"auth": "{{ (dkr_dev_user+':'+dkr_dev_password) | b64encode }}"
}
},
"HttpHeaders": {
"User-Agent": "Docker-Client/19.03.2 (linux)"
}

#ansible #docker
terraform create dockreg secret in k8s

resource "kubernetes_secret" "company-dkr-key" {
metadata {
name = "company-dkr-key"
namespace = "${kubernetes_namespace.company.metadata.0.name}"
}

data = {
".dockerconfigjson" = "{\"auths\":{\"${var.company-dkr-url}\":{\"username\":\"${var.company-dkr-user}\",\"password\":\"${var.company-dkr-password}\",\"email\":\"email\",\"auth\":\"${base64encode(format("%s:%s", var.company-dkr-user, var.company-dkr-password))}\"}}}"

## OR u can also do this from file
# ".dockercfg" = "${file("${path.module}/docker.cfg")}"

}

type = "kubernetes.io/dockercfg"
}

#terraform #docker #kubernetes
как сбросить пароль на postgresql в запущенном docker контейнере без перезапуска

Рубрика "костылим с буквой"

ОСТОРОЖНО прочитанное далее может вызвать кровотечение из глаз и непреодолимое желание расшибить себе лоб рукой.

вы были предупреждены.

Раскатывал я тут хелм сентри... Дано: не работающий Job, который использует пароль из секрета, и криво написанный авторами чарт, в котором слетает пароль пользователя в postgres. Задача - установить в контенере на лету нужный пароль пользователя.



# получаем пароль который должен быть выставлен на постгре
kubectl -n sentry get secret sentry-sentry-postgresql -o yaml | awk '$1=/postgresql-password:/ {print $2}' | base64 -d; echo

# получаем ноду на которой крутится постгре и ssh-шимся на нее
kubectl -n sentry get po -o wide | awk '$1~/.*postgr.*/ {print $7}'

# получаем id контейнера и логинимся туда под рутом
docker ps | grep postgr | grep entry | awk '{print $1}'
docker exec -ti -u0 <container_id> bash

# узнаем пользователя под которым запущен постгре
grep Uid /proc/1/task/1/status

# разрешаем логиниться из-под локалхоста
sed -ibak 's/^\([^#]*\)md5/\1trust/g' /opt/bitnami/postgresql/conf/

# добавляем пользователя в систему и переходим в него
useradd postgres -u 1001
su postgres

# выставляем переменные окружения и релоадим сервис
export PGDATA=/bitnami/postgresql/data
/opt/bitnami/postgresql/bin/pg_ctl reload

# логинимся в postgres и выставляем пароль
psql -U postgres
ALTER USER postgres WITH PASSWORD 'XXX';

возвращаем назад изменения или перестартуем контейнер.


#рукиизжопы #костыли #postgresql #docker #sentry #kubernetes
Happy New Year! With a new year upon us, it's time to reflect on the best Docker content and projects from 2019 sourced from our Docker experts and our exceptional Docker community and community leaders. Check out our most binge-worthy content of 2019 as you begin to map your Docker journey for 2020.

Top 5 Docker Blogs from 2019

Intro Guide to Dockerfile Best Practices by Tibor Vass - July 2, 2019
Happy Pi Day with Docker and Raspberry Pi by Paulo Frazao - March 14, 2019
5 Things to Try with Docker Desktop WSL 2 Tech Preview by Ben De St Paer-Gotch - July 31, 2019
New in Docker Hub: Personal Access Token by Shenea Leven - September 19, 2019
Docker's Next Chapter: Advancing Developer Workflows for Modern Apps by Scott Johnston - November 13, 2019


Top Docker & Docker Captain Projects:

Container registry with commands in an Alpine image
Golang library with API to run Docker container
docker-compose stack for Prometheus monitoring
Sample node app for Docker examples

#docker #подборка