tag:blogger.com,1999:blog-9889743293989030212024-03-14T04:37:58.135+02:00Блог начинающего сисадминаUnknownnoreply@blogger.comBlogger300125tag:blogger.com,1999:blog-988974329398903021.post-51337266445255512932020-02-05T20:24:00.001+02:002020-02-16T12:36:01.935+02:00FOSDEM 2020<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: left;">
В этом году я <a href="https://blog.amet13.name/2019/03/fosdem-2019.html">снова</a> съездил на FOSDEM.</div>
<div class="separator" style="clear: both; text-align: left;">
В связи с тем, что это был юбилейная 20я конференция, то народу там было больше чем в прошлом году. На некоторые доклады попасть было нереально, даже если занимать очередь за час до доклада.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-5AUD6sSEQzU/XjncDa5IruI/AAAAAAAAB1o/1-af32SwcgMTctxTYb_-pFGM6dwXWioegCNcBGAsYHQ/s1600/C7547954-ADD3-42B0-AE5C-7483DDBFC94D_1_105_c.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="768" data-original-width="1024" height="300" src="https://1.bp.blogspot.com/-5AUD6sSEQzU/XjncDa5IruI/AAAAAAAAB1o/1-af32SwcgMTctxTYb_-pFGM6dwXWioegCNcBGAsYHQ/s400/C7547954-ADD3-42B0-AE5C-7483DDBFC94D_1_105_c.jpeg" width="400" /></a></div>
<br />
<br />
В принципе, доклады чуть интереснее в прошлом году для меня. Но в этом году мне удалось прослушать всего 10.<br />
<br />
Вот некоторые из них:<br />
- <a href="https://fosdem.org/2020/schedule/event/tanka/">Introducing Tanka</a> — Grafana Labs выпустили <a href="https://github.com/grafana/tanka">какую-то штуку</a> типа ksonnet, очень спорно, мне так показалось<br />
- <a href="https://fosdem.org/2020/schedule/event/automation/">Over Twenty Years Of Automation</a> — как изменялась автоматизация, начиная от баш-скриптов до Docker<br />
- <a href="https://fosdem.org/2020/schedule/event/velero/">Preserve kubernetes state using heptio velero</a> — неплохой ознакомительный доклад по Velero (бывший Ark)<br />
- <a href="https://fosdem.org/2020/schedule/event/containers_k8s_runtimes/">Below Kubernetes: Demystifying container runtimes</a> — обзор существующих CRI для кубера<br />
- <a href="https://fosdem.org/2020/schedule/event/http3/">HTTP/3 for everyone</a> —отличный доклад по HTTP/3, еще бы, ведь его вел сам создать cURL<br />
- <a href="https://fosdem.org/2020/schedule/event/postgresql_postgresql_on_k8s_at_zalando_two_years_in_production/">PostgreSQL on K8S at Zalando: Two years in production</a> —на этот доклад был прям аншлаг, пришлось час отстоять в очереди и еще час просидеть на предыдущем докладе, чтобы остаться в этой аудитории. В общем как обычно, Zalando крутые ребята и пилят класные штуки, в частности <a href="https://github.com/zalando/patroni">Patroni</a>. Рассказ о том, как PostgreSQL работает в кубере и какие проблемы при этом есть.<br />
<br />
Не удалось попасть на доклад про мониторинг клубники и eBPF+Cilium.<br />
А, ну да, приложение под iOS ужасное, в отличие от Android.<br />
<br />
Записи докладов: <a href="https://video.fosdem.org/2020/">https://video.fosdem.org/2020/</a></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-87374240338268652512019-12-27T21:01:00.000+02:002019-12-27T21:01:21.173+02:00XP Days Ukraine 2019<div dir="ltr" style="text-align: left;" trbidi="on">
22-23 ноября, в Киеве прошла ежегодная конференция XP Days. Доклады были посвящены инженерным практикам, DevOps, архитектуре и т.д.<br />
Конференция шла в три параллельных потока, я отметил что не наблюдал ни одной задержки между докладами, так хорошо все было организовано. Единственное что из-за смены местами одного из докладов, так и не удалось на него попасть. Но зато есть его <a href="https://www.youtube.com/watch?v=NYnq99R0vf0&list=PLrw9xNHk9SGSHy88jY5ja77t-rj79v0PF&index=35&t=0s">запись</a>.<br />
<br />
Несколько докладов, на которых я побывал и они мне понравились:<br />
- Effectiveness tips from Kubernetes trenches by Captain Obvious, <a href="https://xpdays.com.ua/programs/effectiveness-tips-from-kubernetes-trenches-by-captain-obvious/">линк</a><br />
- Lego from Containers, <a href="https://xpdays.com.ua/programs/lego-from-containers/">линк</a><br />- 30 minutes to prod, <a href="https://xpdays.com.ua/programs/30-minutes-to-prod/">линк</a><div>
- Practical GitOps on Kubernetes with ArgoCD, <a href="https://xpdays.com.ua/programs/practical-gitops-on-kubernetes-with-argocd/">линк</a></div>
<div>
- The movement steps to the high-load tolerant and scalable infrastructure based on the AWS and Kubernetes, <a href="https://xpdays.com.ua/programs/the-movement-steps-to-the-high-load-tolerant-and-scalable-infrastructure-based-on-the-aws-and-kubernetes/">линк</a><br /><br /><div>
Плейлист тут: <a href="https://www.youtube.com/playlist?list=PLrw9xNHk9SGSHy88jY5ja77t-rj79v0PF">https://www.youtube.com/playlist?list=PLrw9xNHk9SGSHy88jY5ja77t-rj79v0PF</a></div>
</div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-32946852250416357992019-07-27T14:39:00.001+03:002019-07-27T14:39:37.323+03:00Вопросы на собеседовании на позицию DevOps-инженера которые задавал я<div dir="ltr" style="text-align: left;" trbidi="on">
Я чуть больше года назад оставлял <a href="https://blog.amet13.name/2018/05/devops.html">заметку</a> о том, какие вопросы мне задавали на собеседованиях.<br />
В последние несколько месяцев мне самому доводилось достаточно собеседовать людей, поэтому в этой заметке я расскажу какие вопросы задавал я и почему.<br />
<br />
Техническое интервью с кандидатом у нас занимало примерно 1.5 часа.<br />
Собеседование с применением обычной белой доски (whiteboard) и маркера. Мы не использовали схему вопрос-ответ, а само собеседование шло в виде беседы, по мере которой с каких-то общих тем мы углублялись в конкретные детали.<br />
<br />
В первую очередь мы со своей стороны рассказывали, что у нас за продукт с технической точки зрения, что мы делаем по инфраструктурной части, как проиходит работа в команде платформы и взаимодействие с разработчиками и другими отделами. Объясняли кандидату почему мы сейчас ищем человека в команду, какие ближайшие планы по развитию команды и продукта с технической точки зрения, и т.д.<br />
<br />
По резюме кандидата мы особо не спрашивали, но учитывали во внимание то, что если человек 5 лет работал с сетями и прочими цисками, то нет смысла спрашивать его про модель OSI и что такое пиринг VPC.<br />
<br />
Первый часть с которой мы начинали, это попросили кандидата на доске нарисовать как он видит схему инфраструктуры какого-нибудь веб-проекта. Начиная с самого простенького что у нас просто есть инстанс или железный сервер (мы кстати рекомендовали привязываться к любому удобному облачному провайдеру или вообще bare-metal).<br />
По мере роста инфраструктуры задавались наводящие вопросы по теме:<br />
- как бы ты реализовывал балансинг на инстансах, автоскейлинг группу, и т.д.<br />
- что бы ты делал если начинает расти нагрузка на базу, репликации, индексы, кеш, очереди<br />
- если сломался сервер, как бы ты траблшутил все это<br />
- зачем нужен CDN, как ходит трафик к твоему приложению, зашифрован ли он, на каком этапе происходит терминирование SSL<br />
- как бы ты реализовывал бекапы<br />
- какой мониторинг бы использовал и почему, когда стоит платить деньги за какой-нибудь datadog, а когда уже стоит завозить свой условный Prometheus-стек, то же самое касается логгинга<br />
<br />
Вторая часть плавно переходила в понимание и огранизацию процесса CI/CD.<br />
Как кандидат видит пайплайн, какие инструменты бы он использовал, как поддерживать адекватные косты для всего этого хозяйства (например юзать спот инстансы) и прочее.<br />
<br />
Если у кандидата имелся опыт работы с Kubernetes задавали несколько вопросов по куберу, так как у нас его уже активно используют. Вопросы больше были из разряда:<br />
- какие проблемы решает кубер, а какие нет<br />
- в чем отличие контейнерной виртуализации от полной<br />
- для чего придумали HELM и как его используют<br />
<br />
Обычно этого было достаточно для понятия уровня кандидата. Но иногда если оставалось время, то могли спросить какой-то каверзный вопрос из разряда, где на жестком диске находится каталог /proc или как посмотреть нетстатом established UDP соединения.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-73658233892747362032019-05-25T12:01:00.000+03:002019-06-06T20:50:51.062+03:00DevOps Days Kyiv 2019<div dir="ltr" style="text-align: left;" trbidi="on">
17-18 мая в Киеве прошла ежегодная конференция DevOps Days Kyiv.<br />
<br />
Особенность конференции заключается в том, что доклады посвящены культуре девопса, а не техническим деталям.<br />
Помимо основных докладов можно было выступить со своей темой (ignite talks).<br />
Например были небольшие доклады про Terraform, БД, VictoriaMetrics, звезды на Github, организацию сети в амазоне и много других интересных докладов.<br />
<br />
Помимо докладов, каждый мог предложить какую-либо тему для обсуждения в формате open space, некоторые из обсуждаемых тем второго дня:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-xBVEVyc2iA8/XOkDFEhTaDI/AAAAAAAABzo/dM55mVxhmAk3ig8z36_mW3FaJJxlMY58ACLcBGAs/s1600/61402835_402982143763233_4168701734308282368_o.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1068" data-original-width="1600" height="266" src="https://1.bp.blogspot.com/-xBVEVyc2iA8/XOkDFEhTaDI/AAAAAAAABzo/dM55mVxhmAk3ig8z36_mW3FaJJxlMY58ACLcBGAs/s400/61402835_402982143763233_4168701734308282368_o.jpg" width="400" /></a></div>
<br />
Terraform и СУБД в Kuberentes также были на open space обсуждениях.<br />
В общем конфа получилась интересная, как с организаторской точки зрения, так и со стороны докладов и качества материала.<br />
<br />
Фото: <a href="https://www.facebook.com/pg/devopsdayskyiv/photos/?tab=album&album_id=402849030443211&ref=page_internal">https://www.facebook.com/pg/devopsdayskyiv/photos/?tab=album&album_id=402849030443211&ref=page_internal</a><br />
Слайды презентации: <a href="https://www.slideshare.net/MykolaMarzhan/presentations">https://www.slideshare.net/MykolaMarzhan/presentations</a><br />
Видео докладов: <a href="https://www.youtube.com/playlist?list=PL_O8YSX8ckffzeV9mIBUQniaKFxGnPdYh">https://www.youtube.com/playlist?list=PL_O8YSX8ckffzeV9mIBUQniaKFxGnPdYh</a></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-26239898001409229812019-04-07T12:24:00.004+03:002023-11-06T23:25:07.401+02:00Отправляем метрики из AWS Cloudwatch в Prometheus с помощью prometheus-operator в Kubernetes<div dir="ltr" style="text-align: left;" trbidi="on">Добавляем права нашему пользователю AWS для чтения метрик:</div><div dir="ltr" style="text-align: left;" trbidi="on">
<div>
<span style="font-family: "courier new" , "courier" , monospace;">aws iam attach-group-policy \<br />--policy-arn arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess \<br />--group-name kops-dev</span><br />
<br />
Создаем values-файл для экспортера:</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">cat << EOF > values-cloudwatch-exporter.yml<br />service:<br /> annotations:<br /> prometheus.io/scrape: "true"<br />EOF</span><br />
<br />
Устанавливаем <a href="https://github.com/helm/charts/tree/master/stable/prometheus-cloudwatch-exporter">экспортер</a>:</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">helm install stable/prometheus-cloudwatch-exporter \<br />--name prometheus-cloudwatch-exporter \<br />--namespace kube-system \<br />--set aws.aws_access_key_id=${AWS_ACCESS_KEY_ID} \<br />--set aws.aws_secret_access_key=${AWS_SECRET_ACCESS_KEY} \<br />-f values-cloudwatch-exporter.yml</span><br />
<br />
<br />
Создаем values-файл для оператора:</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">cat << EOF > values-operator.yml<br />prometheus:<br /> additionalServiceMonitors:<br /> - name: prometheus-operator-cloudwatch<br /> endpoints:<br /> - port: http<br /> path: /metrics<br /> interval: 30s<br /> namespaceSelector:<br /> matchNames:<br /> - kube-system<br /> selector:<br /> matchLabels:<br /> app: prometheus-cloudwatch-exporter<br />serviceMonitors:<br /> - name: ""<br /> namespaceSelector:<br /> any: true<br />EOF</span><br />
<br />
Устанавливаем <a href="https://github.com/helm/charts/tree/master/stable/prometheus-operator">prometheus-operator</a> с Alertmanager и Grafana:</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">helm install stable/prometheus-operator \<br />--name prometheus-operator \<br />--namespace monitoring \<br />-f values-operator.yml</span><br />
<br />
Идем в дашборд прометеуса на страницу Targets и проверяем наш новый таргет:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-OMie8PtSet4/XKnBnIkDrWI/AAAAAAAAByo/rQrETka1tCQ4T3WkJxYxgA-S5iOX0JgAwCLcBGAs/s1600/1_4D8AI1ETwZuvcM5kWQSIOg.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="260" data-original-width="1600" height="62" src="https://2.bp.blogspot.com/-OMie8PtSet4/XKnBnIkDrWI/AAAAAAAAByo/rQrETka1tCQ4T3WkJxYxgA-S5iOX0JgAwCLcBGAs/s400/1_4D8AI1ETwZuvcM5kWQSIOg.png" width="400" /></a></div>
<div style="text-align: center;">
<br /></div>
<div>
<br />
Ну и наконец посмотрим сами метрики:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-zxrobIBRsWc/XKnBuxUJ2rI/AAAAAAAABys/L230mtiGGcoFcJOrtDkh_wG2AxBUjv5xQCLcBGAs/s1600/1_3js-1sL9sqgHOygnb1FmDg.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="1600" height="148" src="https://1.bp.blogspot.com/-zxrobIBRsWc/XKnBuxUJ2rI/AAAAAAAABys/L230mtiGGcoFcJOrtDkh_wG2AxBUjv5xQCLcBGAs/s400/1_3js-1sL9sqgHOygnb1FmDg.png" width="400" /></a></div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-38964033925256862192019-03-09T13:22:00.001+02:002020-01-23T10:21:47.435+02:00FOSDEM 2019<div dir="ltr" style="text-align: left;" trbidi="on">
2-3 февраля мне удалось побывать на ежегодной конференции <a href="https://fosdem.org/2019/schedule/">FOSDEM</a>.<br />
Конфа полностью бесплатная, проводилась на базе университета Брюсселя, примерно в часе пешком от центра Брюсселя.<br />
Народу было много, гитхаб разливал кофеек бесплатно:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-5ascwpyVfzQ/XIOc_RFiNQI/AAAAAAAABxU/qwPZWidNqREN79CC0UFnYGNDCtTWWtRUQCLcBGAs/s1600/2019-02-03%2B09.57.29.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="300" src="https://3.bp.blogspot.com/-5ascwpyVfzQ/XIOc_RFiNQI/AAAAAAAABxU/qwPZWidNqREN79CC0UFnYGNDCtTWWtRUQCLcBGAs/s400/2019-02-03%2B09.57.29.jpg" width="400" /></a></div>
<div style="text-align: center;">
<br /></div>
Докладов было очень много, но не всегда можно было попасть на те которые хочется из-за большого количества народу.<br />
Помимо самих докладов, было множество интересных стендов, на некоторых даже можно было взять пивко за донат или сделать себе значок с логотипом Gentoo собственными руками:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/--FzPEGYoJq4/XIOdfWoZj-I/AAAAAAAABxc/anzZ_WIHr5MdbvH_fSbKZ877O8gXrRu9wCLcBGAs/s1600/2019-02-02%2B14.16.06.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="400" src="https://4.bp.blogspot.com/--FzPEGYoJq4/XIOdfWoZj-I/AAAAAAAABxc/anzZ_WIHr5MdbvH_fSbKZ877O8gXrRu9wCLcBGAs/s400/2019-02-02%2B14.16.06.jpg" width="300" /></a></div>
<div style="text-align: center;">
<br /></div>
Теперь пару слов о докладах, на которых я побывал (тут неполный список, только те что я сходу нашел):<br />
- <a href="https://fosdem.org/2019/schedule/event/deploying_postgresql_on_kubernetes/">Deploying PostgreSQL on Kubernetes</a> — ожидал услышать хардкора, но по факту рассказывалось про базовые вещи кубера и что постгрес можно деплоить ямликами, хелмом или оператором<br />
- <a href="https://fosdem.org/2019/schedule/event/mysql_replication_advance/">MySQL Replication - Advanced Features</a> — Петр Зайцев рассказал об истории появления различных репликаций в MySQL, чем отличаются различные типы репликаций и т.д.<br />
- <a href="https://fosdem.org/2019/schedule/event/loki_prometheus_for_logs/">Loki - Prometheus for logs</a> — презентация тулзы для логов от создателей Grafana, выглядит круто, посмотрим как покажет себя на деле<br />
- <a href="https://fosdem.org/2019/schedule/event/containers_kubectl_trace/">Introducing kubectl-trace</a> — вроде что-то про трассировку в кубере, толком не смотрел доклад, так как в это время чинил стейджевый куберовский кластер :)<br />
- <a href="https://fosdem.org/2019/schedule/event/containers_k8s_storage/">Upcoming Kubernetes Storage features</a> — TLDR: скоро можно будет PVC мувать между неймспейсами, клонировать PVC и создавать Populating PVC (т.е. при создании PVC сразу же на него например клонировать код из git-репозитория или скачивать файл по http, что-то на манер packer)<br />
- <a href="https://fosdem.org/2019/schedule/event/postgresql11/">PostgreSQL Goes to 11!</a> — немного истории постгреса и обзор чейнджлога к 11 версии<br />
- <a href="https://fosdem.org/2019/schedule/event/netflix_freebsd/">Netflix and FreeBSD</a> — доклад о том, как Netflix поддерживают свою кодовую базу FreeBSD, почему и как они гоняют большой траффик на своих CDN с помощью FreeBSD<br />
- <a href="https://fosdem.org/2019/schedule/event/cloud_is_another_sun/">The Cloud is Just Another Sun</a> — история о том, как было раньше с серверами, как сейчас все в облаках и что надо делать дальше<br />
- <a href="https://fosdem.org/2019/schedule/event/keynote_fifty_years_unix/">2019 - Fifty years of Unix and Linux advances</a> — maddog интересно рассказал, как разивался Unix, GNU, Linux, open source, в интересной форме</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-55811531751334878242019-02-09T13:27:00.000+02:002019-02-09T13:27:02.401+02:00Миграция сообщений в очередях RabbitMQ с помощью Shovel<div dir="ltr" style="text-align: left;" trbidi="on">
У RabbitMQ существует возможность миграции сообщений между очередями, как в пределах одной ноды, так и между различными нодами.<br />
Для этого можно использовать плагин <a href="https://www.rabbitmq.com/shovel.html">Shovel</a> (вообще кроме Shovel полезно будет знать про <a href="https://www.rabbitmq.com/federation.html">федерацию</a> и <a href="https://www.rabbitmq.com/clustering.html">кластеризацию</a> в RabbitMQ, в некоторых кейсах можно использовать и их).<br />
<br />
Установка плагина Shovel:<br />
<span style="font-family: Courier New, Courier, monospace;">rabbitmq-plugins enable rabbitmq_shovel rabbitmq_shovel_management</span><br />
<br />
Пример использования Shovel для миграции очереди celery с ноды <span style="font-family: Courier New, Courier, monospace;">node1</span> на <span style="font-family: Courier New, Courier, monospace;">node2</span>:<br />
<span style="font-family: Courier New, Courier, monospace;">rabbitmqctl set_parameter shovel celery-migration \</span><br />
<span style="font-family: Courier New, Courier, monospace;">'{"src-uri": "amqp://node1user:node1password@node1ip/node1vhost", "src-queue": "celery", "dest-uri": "amqp://node2user:node2password@node2ip/node2vhost", "dest-queue": "celery"}'</span><br />
<br />
Для того чтобы <span style="font-family: Courier New, Courier, monospace;">node1</span> могла подключиться к <span style="font-family: Courier New, Courier, monospace;">node2</span>, на второй должен быть открыть порт 5672.<br />
Помимо использования CLI можно и использовать веб-интерфейс, пример можно посмотреть <a href="https://www.cloudamqp.com/docs/shovel.html">тут</a>.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-85974420511981130342019-01-23T20:19:00.000+02:002019-04-12T08:33:59.070+03:00Пробрасываем реальный IP-адрес в Nginx Ingress от Cloudfront<div dir="ltr" style="text-align: left;" trbidi="on">
По умолчанию установленный <a href="https://github.com/helm/charts/tree/master/stable/nginx-ingress">Nginx Ingress</a> с помощью HELM в AWS не пробрасывает реальный IP-адрес внутрь балансера, поэтому в логах ингресс-контроллера будут присутствовать логи с внутренних адресов сети.<br />
<br />
В каком случае нам нужно иметь реальный адрес? Например если мы хотим на уровне ингресса или приложения анализировать адреса или для их блокировки.<br />
Делается это несложно.<br />
<br />
Включаем аннотацию для прокси в сервисе контроллера:<br />
<span style="font-family: "courier new" , "courier" , monospace;">kubectl edit svc nginx-ingress-controller -n kube-system</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">metadata:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">...</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> annotations:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: '*'</span><br />
<br />
Разрешаем в конфигмапе использование прокси, добавляем список адресов Cloudfront и перезаписываем <span style="font-family: Courier New, Courier, monospace;">the_real_ip</span>:<br />
<span style="font-family: "courier new" , "courier" , monospace;">kubectl edit configmap nginx-ingress-controller -n kube-system</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">data:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">...</span><br />
<span style="font-family: courier new, courier, monospace;"> # curl -s https://ip-ranges.amazonaws.com/ip-ranges.json | jq -r '.prefixes[] | select(.service=="CLOUDFRONT") | .ip_prefix' | awk '{print $1}'</span><br />
<span style="font-family: courier new, courier, monospace;"> proxy-real-ip-cidr: "54.155.0.0/16,172.96.98.0/24..."</span><br />
<span style="font-family: courier new, courier, monospace;"> http-snippet: |</span><br />
<span style="font-family: courier new, courier, monospace;"> map '' $the_real_ip {</span><br />
<span style="font-family: courier new, courier, monospace;"> default $http_x_forwarded_for;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"></span><br />
<span style="font-family: courier new, courier, monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> use-proxy-protocol: "true"</span><br />
<br />
Собственно говоря после этого все.<br />
Идем в логи контроллера и смотрим адреса с которого приходят запросы:<br />
<span style="font-family: "courier new" , "courier" , monospace;">kubectl logs -f nginx-ingress-controller-56f4bf4dc9-5pqjn</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">1.1.1.1 - [1.1.1.1] - - [22/Jan/2019:18:58:23 +0000] "GET /ping HTTP/1.1" 503 197 "-" "Wget" 85 0.000 [-]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
В самом конфиге ингресса добавляем:<br />
<span style="font-family: "courier new" , "courier" , monospace;"> nginx.ingress.kubernetes.io/server-snippet: |</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> real_ip_header X-Forwarded-For;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> real_ip_recursive on;</span></div>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-988974329398903021.post-61127866603030972622018-12-15T12:22:00.000+02:002018-12-15T12:22:13.414+02:00Создание read-only пользователя в PostgreSQL<div dir="ltr" style="text-align: left;" trbidi="on">
Источник: <a href="https://gist.github.com/oinopion/4a207726edba8b99fd0be31cb28124d0">https://gist.github.com/oinopion/4a207726edba8b99fd0be31cb28124d0</a><br />
<br />
Сохраню себе для копипасты.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">-- Create a group</span><br />
<span style="font-family: Courier New, Courier, monospace;">CREATE ROLE readaccess;</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">-- Grant access to existing tables</span><br />
<span style="font-family: Courier New, Courier, monospace;">GRANT USAGE ON SCHEMA public TO readaccess;</span><br />
<span style="font-family: Courier New, Courier, monospace;">GRANT SELECT ON ALL TABLES IN SCHEMA public TO readaccess;</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">-- Grant access to future tables</span><br />
<span style="font-family: Courier New, Courier, monospace;">ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readaccess;</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">-- Create a final user with password</span><br />
<span style="font-family: Courier New, Courier, monospace;">CREATE USER user WITH PASSWORD 'secret';</span><br />
<span style="font-family: Courier New, Courier, monospace;">GRANT readaccess TO user;</span></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-8311095599268862772018-11-03T19:53:00.001+02:002018-11-03T19:53:19.357+02:00Видео докладов с конференции DevOps Stage 2018<div dir="ltr" style="text-align: left;" trbidi="on">
В середине октября прошла двухдневная конференция в Киеве DevOps Stage.<br />
Доклады были разбиты на три категории:<br />
<br />
<ul style="text-align: left;">
<li><a href="https://www.youtube.com/playlist?list=PL2DFnm8LBPXon5COYCef3ewmAVrAfbPdZ">METHODOLOGY / DEVSECOPS / ARCHITECTURE</a></li>
<li><a href="https://www.youtube.com/playlist?list=PL2DFnm8LBPXod2GcsAmfW9piiWaVuEbcN">APPROACH / TOOLSET</a></li>
<li><a href="https://www.youtube.com/playlist?list=PL2DFnm8LBPXoHAgDALNAr0c0hV4ua-NnS">PLATFORM / CLOUD</a></li>
</ul>
<br />
Само собой все доклады мне посетить не удалось, но могу выделить для себя те, которые понравились больше всего.<br />
<br />
<b>Yevhen Volchenko | <a href="https://youtu.be/-Ez8jc5xQfs">KUBERNETES ATTACK SURFACES AND WAYS TO SECURE THEM</a></b><br />
Практические советы о том как защитить Kubernetes.<br />
Хорошие пояснения что и почему надо защищать с примерами конфигураций.<br />
<br />
<b>Volodymyr Tsap | <a href="https://youtu.be/U_TmqG7tCto">ON THE ROAD TO 6.9K. HOW TO SUCCEED IN TECHNICAL INTERVIEW</a></b><br />
Мем про 6.9к известен в киевской девопс-тусовке (ссылку на статью не оставляю, но гуглится по запросу "DevOps с комплексом бога запросил зарплату в $6.9К").<br />
Доклад интересен прежде всего интересной подачей с кучей лулзов.<br />
В докладе интересно рассказывается про описание работы инженера, с какими технологиями он работает, что должен знать, какие вопросы обычно задают на собеседовании и прочее.<br />
<br />
<b>Yurii Rochniak | <a href="https://youtu.be/Pi8CXBV3ZIU">CI DOESN’T START WITH JENKINS</a></b><br />
Юра рассказывает про то как мы пытаемся варить девопс в Preply, какие технологии и тулы используем, как эволюционируем и почему.<br />
Одним из вопросов из зала был, как мы раним Kubernetes на спот-инстансах в AWS, после чего Юра написал <a href="https://medium.com/preply-engineering/why-and-how-do-we-run-kubernetes-on-the-spot-instances-c88d32fb9df3">полноценную статью</a>, которая отвечает на этот вопрос.<br />
<br />
<b>Juliya Tkachova | <a href="https://youtu.be/W3IoyZnPeFw">DEVOPS ON SCALE FROM PHILOSOPHY TO TOOLSET</a></b><br />
В этом докладе рассказывается про девопс со множеством примеров факапов.<br />
Причем название доклада полностью описывает его содержание, поэтому интересен как со стороны философии, так и со стороны набора инструментов и технологий.<br />
<br />
Был еще один хороший доклад от Mark Smalley, но я его не нашел в тех плейлистах.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-19045463189175914152018-10-13T23:17:00.001+03:002023-11-06T23:25:42.633+02:00Видео докладов с конференции OSDN 2018<div dir="ltr" style="text-align: left;" trbidi="on">
В сети появились записи докладов с конференции на <a href="https://www.youtube.com/watch?v=QQk2Ci7z4s4&list=PLacPOdvNyGDBP9nvLo_-lag5v1c3SHTTK">youtube</a>. Конференция проводится уже не первый раз в Киеве, в этом году она была в сентябре.<br />
<br />
Рекомендую к просмотру доклады:<br />
<div>
— Леннарта Поттеринга — Locking Down Your Systemd Services (Леннарта слушать интересно)<div style="text-align: center;">
<br /></div>
</div>
<div>
— Максима Богука — Использование статистики в PostgreSQL для оптимизации производительности (узнал для себя много нового про Postgres)</div>
<div>
<br /></div>
<div>
Также мне было интересно послушать доклад Николая Маржана — Amazon RDS Monitoring, так как я использую PostgreSQL в амазоновском RDS.</div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-59398384871118476362018-10-07T20:39:00.000+03:002018-10-07T20:39:35.201+03:00Долой cat и less, да здравствует bat!<div dir="ltr" style="text-align: left;" trbidi="on">
<a href="https://github.com/sharkdp/bat">https://github.com/sharkdp/bat</a><br />
<br />
Что умеет:<br />
- подсветка номеров строк и синтаксиса (довольно много различных языков и разметок)<br />
- если содержимое файла влезает в экран, работает как <span style="font-family: "courier new" , "courier" , monospace;">cat</span>, если нет — как <span style="font-family: "courier new" , "courier" , monospace;">less</span><br />
- поддержка <span style="font-family: "courier new" , "courier" , monospace;">git diff</span><br />
- поддержка конкатенации файлов, равно как и <span style="font-family: "courier new" , "courier" , monospace;">cat</span><br />
<span style="font-family: inherit;">- при этом все эти штуки можно включать и отключать как удобно</span><br />
<br />
Как привыкаем:<br />
<span style="font-family: "courier new" , "courier" , monospace;">echo alias cat='bat' >> ~/.bash_profile</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">echo alias less='bat' >> ~/.bash_profile</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">source ~/.bash_profile</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">cat README.md</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-cPpAWT9xl14/W7pED9KS7JI/AAAAAAAABwE/TsvXn6QWyrUYhRhaWi7T-iocns1jiiR-QCLcBGAs/s1600/bat.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1251" data-original-width="1600" height="311" src="https://2.bp.blogspot.com/-cPpAWT9xl14/W7pED9KS7JI/AAAAAAAABwE/TsvXn6QWyrUYhRhaWi7T-iocns1jiiR-QCLcBGAs/s400/bat.png" width="400" /></a></div>
<div style="text-align: center;">
<br /></div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-17171116047092085712018-09-29T20:05:00.002+03:002018-10-02T22:32:19.364+03:00Бекапим все свои репозитории локально с GitHub<div dir="ltr" style="text-align: left;" trbidi="on">
Идем в настройки и генерируем токен с правами repo: <a href="https://github.com/settings/tokens">https://github.com/settings/tokens</a><br />
<br />
Запускаем бекап на локальную машину всех своих репозиториев:<br />
<div>
<span style="font-family: "courier new" , "courier" , monospace;">export GITHUB_AT=yourtokenfromgithub</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">export USERNAME=Amet13<br />curl -s https://$GITHUB_AT:@api.github.com/users/$USERNAME/repos?per_page=200 | \</span><br />
<div>
<span style="font-family: "courier new" , "courier" , monospace;">jq .[].ssh_url | \</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">xargs -n 1 git clone</span><br />
<br />
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #f2f2f2; background-color: #000000}
span.s1 {font-variant-ligatures: no-common-ligatures}
</style></div>
<div>
На случай пожара, так сказать.</div>
</div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-15433974393500969702018-09-08T14:50:00.002+03:002018-09-08T14:50:51.543+03:00Автоскейлинг нод в Kubernetes<div dir="ltr" style="text-align: left;" trbidi="on">
В <a href="https://blog.amet13.name/2018/09/kubernetes-kops-aws.html">этой</a> заметке мы устанавливали кластер Kubernetes в AWS с помощью kops.<br />
А в данной заметке я опишу настройки автоскейлинга нод в Kubernetes.<br />
<br />
Для того чтобы автоскейлинг работал, необходимо <a href="https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler">его</a> установить в кластер в неймспейс <span style="font-family: Courier New, Courier, monospace;">kube-system</span>.<br />
<br />
Перед непосредственной установкой, убедитесь что на всех нодах, которые вы хотите скейлить есть соответствующие лейблы:<br />
<span style="font-family: Courier New, Courier, monospace;">kops get ig</span><br />
<span style="font-family: Courier New, Courier, monospace;">kops edit ig nodes</span><br />
<span style="font-family: Courier New, Courier, monospace;">...</span><br />
<span style="font-family: Courier New, Courier, monospace;">spec:</span><br />
<span style="font-family: Courier New, Courier, monospace;"> cloudLabels:</span><br />
<span style="font-family: Courier New, Courier, monospace;"> k8s.io/cluster-autoscaler/enabled: ""</span><br />
<span style="font-family: Courier New, Courier, monospace;"> kubernetes.io/cluster/k8s-dev.domain.org: ""</span><br />
<br />
Эта команда будет создавать ноды с соответствующими лейблами, поэтому важно повесить лейблы также и на существующие ноды.<br />
<br />
Подготовим файл конфигурации для автоскейлера:<br />
<span style="font-family: Courier New, Courier, monospace;">cat << EOF > values.yml</span><br />
<span style="font-family: Courier New, Courier, monospace;">autoDiscovery:</span><br />
<span style="font-family: Courier New, Courier, monospace;"> clusterName: k8s-dev.domain.org</span><br />
<span style="font-family: Courier New, Courier, monospace;">awsRegion: eu-west-1</span><br />
<span style="font-family: Courier New, Courier, monospace;">cloudProvider: aws</span><br />
<span style="font-family: Courier New, Courier, monospace;">extraArgs:</span><br />
<span style="font-family: Courier New, Courier, monospace;"> balance-similar-node-groups: true</span><br />
<span style="font-family: Courier New, Courier, monospace;"> expander: random</span><br />
<span style="font-family: Courier New, Courier, monospace;"> skip-nodes-with-system-pods=false: false</span><br />
<span style="font-family: Courier New, Courier, monospace;">rbac:</span><br />
<span style="font-family: Courier New, Courier, monospace;"> create: true</span><br />
<span style="font-family: Courier New, Courier, monospace;"> pspEnabled: true</span><br />
<span style="font-family: Courier New, Courier, monospace;">scale-down-delay: 5m</span><br />
<span style="font-family: Courier New, Courier, monospace;">v: 2</span><br />
<span style="font-family: Courier New, Courier, monospace;">EOF</span><br />
<br />
Установка автоскейлера:<br />
<span style="font-family: Courier New, Courier, monospace;">helm install stable/cluster-autoscaler --name autoscaler -f values.yml</span><br />
<br />
На этом в принципе все, можно позапускать в кластере каких-нибудь нагрузочных тестов, чтобы убедиться в работоспособности скейлинга.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-29206760720905489822018-09-01T10:49:00.001+03:002018-09-08T14:46:02.988+03:00Установка Kubernetes с помощью kops в AWS<div dir="ltr" style="text-align: left;" trbidi="on">
В этой заметке я опишу, как быстро с нуля поднять рабочий кластер k8s в облаке амазона.<br />
Если у вас много денег, можете использовать EKS (который еще недоступен во многих регионах), в качестве альтернативы я использую именно связку AWS+kops.<br />
<br />
Ставим необходимые пакеты для работы с кубером (моя локальная ОС Mac OS X)<br />
<span style="font-family: "courier new" , "courier" , monospace;">brew update</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">brew install awscli kubectl kops kubernetes-helm</span><br />
<br />
<a name='more'></a>Готовим некоторые переменные:<br />
<span style="font-family: "courier new" , "courier" , monospace;">cat <<EOT > .env</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export KOPS_ENV=dev</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export EMAIL=your@email.com # пригодится позже</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">EOT</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">source .env</span><br />
<br />
Создаем группу пользователя для работы в облаке амазона:<br />
<span style="font-family: "courier new" , "courier" , monospace;">aws iam create-group --group-name kops-${KOPS_ENV}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/AmazonEC2FullAccess --group-name kops-${KOPS_ENV}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/AmazonRoute53FullAccess --group-name kops-${KOPS_ENV}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess --group-name kops-${KOPS_ENV}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/IAMFullAccess --group-name kops-${KOPS_ENV}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/AmazonVPCFullAccess --group-name kops-${KOPS_ENV}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">aws iam create-user --user-name kops-${KOPS_ENV}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">aws iam add-user-to-group --user-name kops-${KOPS_ENV} --group-name kops-${KOPS_ENV}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">aws iam create-access-key --user-name kops-${KOPS_ENV}</span><br />
<br />
Используем новые креды пользователя, которые мы получили:<br />
<span style="font-family: "courier new" , "courier" , monospace;">cat <<EOT >> .env</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export AWS_ACCESS_KEY_ID=AAA</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export AWS_SECRET_ACCESS_KEY=BBB</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">export DOMAIN=k8s-${KOPS_ENV}.domain.org</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export ZONE_ID=Z1UJ9MQQPGMX38 # domain.org zone ID (см. Amazon Console Route53)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">EOT</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">source .env</span><br />
<br />
Создаем зону для домена:<br />
<span style="font-family: "courier new" , "courier" , monospace;">ID=$(uuidgen)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">aws route53 create-hosted-zone --name ${DOMAIN} --caller-reference ${ID}</span><br />
<br />
И достаем созданную зону:<br />
<span style="font-family: "courier new" , "courier" , monospace;">SUBDOMAIN_ZONE_ID=$(aws route53 list-hosted-zones-by-name --dns-name ${DOMAIN} --max-items 1 --output json | jq '.HostedZones[].Id' | awk -F '/' '{print $3}' | tr -d '"')</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">cat <<EOT >> .env</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export SUBDOMAIN_ZONE_ID=${SUBDOMAIN_ZONE_ID} # k8s-dev.domain.org zone ID</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">EOT</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">source .env</span><br />
<br />
Теперь нужно получить днс-сервера зоны:<br />
<span style="font-family: "courier new" , "courier" , monospace;">aws route53 get-hosted-zone --id ${SUBDOMAIN_ZONE_ID} --output json | jq '.DelegationSet.NameServers[]' | tr -d '"'</span><br />
<br />
Генерируем json-файл с днс-серверами (замените <span style="font-family: "courier new" , "courier" , monospace;">${NS_1,2,3,4}</span> валидными днс-серверами:<br />
<span style="font-family: "courier new" , "courier" , monospace;">cat << EOF > json/${DOMAIN}.json</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">{</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> "Comment": "Create a ${DOMAIN} NS record in the parent domain",</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> "Changes": [</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> "Action": "CREATE",</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> "ResourceRecordSet": {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> "Name": "${DOMAIN}",</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> "Type": "NS",</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> "TTL": 300,</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> "ResourceRecords": [</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> "Value": "${NS_1}"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> },</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> "Value": "${NS_2}"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> },</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> "Value": "${NS_3}"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> },</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> "Value": "${NS_4}"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> ]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> ]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">EOF</span><br />
<br />
Привяжем субдомен к домену:<br />
<span style="font-family: "courier new" , "courier" , monospace;">aws route53 change-resource-record-sets --hosted-zone-id ${ZONE_ID} --change-batch file://json/${DOMAIN}.json</span><br />
<br />
И проверим доступность зоны:<br />
<span style="font-family: "courier new" , "courier" , monospace;">dig ns ${DOMAIN} +short</span><br />
<br />
Создадим бакет для kops и включим версионирование для него:<br />
<span style="font-family: "courier new" , "courier" , monospace;">aws s3api create-bucket --bucket ${DOMAIN} --region eu-west-1 --create-bucket-configuration LocationConstraint=eu-west-1</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">aws s3api put-bucket-versioning --bucket ${DOMAIN} --versioning-configuration Status=Enabled</span><br />
<br />
Добавим еще некоторые переменные:<br />
<span style="font-family: "courier new" , "courier" , monospace;">cat <<EOT >> .env</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export NAME=${DOMAIN}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export KOPS_STATE_STORE=s3://${DOMAIN}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export ZONES=eu-west-1a</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export INSTANCE_TYPE=m5.large</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">EOT</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">source .env</span><br />
<br />
Сгенерируем SSH-ключ для доступа к кластеру:<br />
<span style="font-family: "courier new" , "courier" , monospace;">ssh-keygen -f ~/.ssh/k8s-${KOPS_ENV} -C admin@${DOMAIN} -N ''</span><br />
<br />
Создадим стейт кластера в бакете:<br />
<span style="font-family: "courier new" , "courier" , monospace;">kops create cluster \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--name=${NAME} \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--zones ${ZONES} \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--master-zones ${ZONES} \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--node-count=2 \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--node-size=${INSTANCE_TYPE} \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--master-count=1 \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--master-size=${INSTANCE_TYPE} \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--cloud=aws \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--kubernetes-version=1.10.5 \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--image kope.io/k8s-1.10-debian-stretch-amd64-hvm-ebs-2018-08-17 \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--ssh-public-key=~/.ssh/k8s-${KOPS_ENV}.pub</span><br />
<br />
Если это дев кластер, то его можно запускать на спот-инстансах, так получится дешевле.<br />
Вот ценник на них: <a href="https://aws.amazon.com/ec2/spot/pricing/">https://aws.amazon.com/ec2/spot/pricing/</a><br />
Для мастеров я использовать спот-инстанс не буду, а для нод буду.<br />
<br />
Настроим спот-инстансы и установим максимальное кол-во нод:<br />
<span style="font-family: Courier New, Courier, monospace;">kops edit instancegroups nodes --name ${NAME} --state=s3://${NAME}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">...</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">spec:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> maxPrice: "0.042"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> maxSize: 4</span><br />
<br />
Непосредственно инициируем создание кластера:<br />
<span style="font-family: "courier new" , "courier" , monospace;">kops update cluster --name=${NAME} --yes</span><br />
<br />
Wait for 5 min and check cluster status:<br />
Ждем некоторое время, попутно проверяя состояние кластера:<br />
<span style="font-family: "courier new" , "courier" , monospace;">kops validate cluster --name=${NAME} | tail -1</span><br />
<br />
Проверяем SSH-доступ к мастеру:<br />
<span style="font-family: "courier new" , "courier" , monospace;">ssh -i ~/.ssh/k8s-${KOPS_ENV} admin@api.${DOMAIN} \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-o StrictHostKeyChecking=no \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-o UserKnownHostsFile=/dev/null</span><br />
<br />
На этом базовая установка кластера окончена.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-62444784415303478252018-07-21T22:02:00.000+03:002018-08-04T11:22:37.706+03:00Mac OS X Mojave beta и чекбоксы в Google Chrome<div dir="ltr" style="text-align: left;" trbidi="on">
Google Chrome пока еще не поддерживает Mac OS Mojave и некорректно отображает чекбоксы (и не только, например некоторые кнопки также не отображаются).<br />
<br />
<div>
Чтобы обойти это, существует <a href="https://chrome.google.com/webstore/detail/mojave-checkbox-fix/ihlgehdlkphgngjfagonbeoepadbdaae/related">плагин</a> для хрома, который устанавливаем размер каждой страницы 1.000001, что является костылем, до тех пор, пока Chrome не начнет поддерживать Mojave.</div>
<div>
<br /></div>
<div>
До плагина:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-G6UHphRdxUQ/W1OC8tz863I/AAAAAAAABvU/_dPRekfQG7MXxKKgx27uPxhhuWenhdLCwCLcBGAs/s1600/Screen%2BShot%2B2018-07-21%2Bat%2B21.57.48.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="251" data-original-width="1600" height="61" src="https://1.bp.blogspot.com/-G6UHphRdxUQ/W1OC8tz863I/AAAAAAAABvU/_dPRekfQG7MXxKKgx27uPxhhuWenhdLCwCLcBGAs/s400/Screen%2BShot%2B2018-07-21%2Bat%2B21.57.48.png" width="400" /></a></div>
<div>
После:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-8m4ZByGF1Ds/W1ODC__U8RI/AAAAAAAABvY/QIBFv8I-iQshaY9o2GIpuvWa0eNpzU3iQCLcBGAs/s1600/Screen%2BShot%2B2018-07-21%2Bat%2B21.58.25.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="205" data-original-width="1600" height="50" src="https://2.bp.blogspot.com/-8m4ZByGF1Ds/W1ODC__U8RI/AAAAAAAABvY/QIBFv8I-iQshaY9o2GIpuvWa0eNpzU3iQCLcBGAs/s400/Screen%2BShot%2B2018-07-21%2Bat%2B21.58.25.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Если еще кому-то интересно, то я заметил еще несколько багов, которые пока не поправили:</div>
<div class="separator" style="clear: both; text-align: left;">
Dropbox, как-то странно отображается окно:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-UuRoFyDx8Ro/W1OD01MOLeI/AAAAAAAABvg/W9eRp8TzIY8O1deLwnbLZFRuw4U0ovDngCLcBGAs/s1600/Screen%2BShot%2B2018-07-21%2Bat%2B22.03.52.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="936" data-original-width="735" height="400" src="https://4.bp.blogspot.com/-UuRoFyDx8Ro/W1OD01MOLeI/AAAAAAAABvg/W9eRp8TzIY8O1deLwnbLZFRuw4U0ovDngCLcBGAs/s400/Screen%2BShot%2B2018-07-21%2Bat%2B22.03.52.png" width="313" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
TextEdit, не всегда закрывается с первого раза.</div>
<div class="separator" style="clear: both; text-align: left;">
Был также баг в Finder, при котором нельзя было из бокового меню извлечь внешний носитель, но это поправили.</div>
<div class="separator" style="clear: both; text-align: left;">
VirtualBox не работает на Mojave.</div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-79269299970417381032018-07-16T20:04:00.000+03:002018-07-16T20:04:16.974+03:00Как скопировать права роли в PostgreSQL<div dir="ltr" style="text-align: left;" trbidi="on">
Все очень просто, у нас есть роль olduser и мы хотим чтобы у нового пользователя newuser были такие же права на таблицы как и у olduser:<br />
<span style="font-family: Courier New, Courier, monospace;">CREATE ROLE newuser WITH LOGIN PASSWORD 'password' CREATEDB CREATEROLE;</span><br />
<span style="font-family: Courier New, Courier, monospace;">GRANT olduser TO newuser;</span></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-86986868745894723892018-07-13T15:13:00.000+03:002018-07-13T20:01:18.204+03:00Обновление версии PostgreSQL в Amazon RDS без даунтайма<div dir="ltr" style="text-align: left;" trbidi="on">
Цель: обновить инстанс PostgreSQL, который работает на версии 9.4 до 9.5.<br />
<br />
RDS не позволяет обновлять PostgreSQL на несколько мажорных версий, поэтому если нужно обновиться например с 9.4 до 10, то итерацию придется повторять несколько раз.<br />
<br />
Также важно то, чтобы были доступы для <span style="font-family: "courier new" , "courier" , monospace;">rds_superuser</span>, без этого не получится настроить репликацию.<br />
<br />
Пример как это все работает на тестовом стенде я описал ниже.<br />
<br />
<a name='more'></a>Создаем наш RDS-инстанс:<br />
<span style="font-family: "courier new" , "courier" , monospace;">export PGUSERNAME=admin_rds</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export PGPASSWORD=admin_rds_pass</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">aws rds create-db-instance \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--db-instance-identifier upgrade-tests \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--allocated-storage 5 \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--db-instance-class db.t2.micro \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--engine postgres \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--master-username ${PGUSERNAME} \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--master-user-password ${PGPASSWORD} \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--engine-version 9.4.15</span><br />
<br />
Заполним нашу базу тестовыми данными:<br />
<span style="font-family: "courier new" , "courier" , monospace;">PGENDPOINT=$(aws rds describe-db-instances --db-instance-identifier upgrade-tests | grep Address | awk '{print $4}')</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT} -p 5432 -U ${PGUSERNAME} postgres -c "CREATE DATABASE sample;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">wget http://pgfoundry.org/frs/download.php/527/world-1.0.tar.gz</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">tar xzf world-1.0.tar.gz</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT} -p 5432 -U ${PGUSERNAME} sample < dbsamples-0.1/world/world.sql</span><br />
<br />
Снимаем снапшот с базы:<br />
<span style="font-family: "courier new" , "courier" , monospace;">aws rds create-db-snapshot \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--db-snapshot-identifier upgrade-tests-snapshot \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--db-instance-identifier upgrade-tests</span><br />
<br />
Убеждаемся что, снапшот в статусе available:<br />
<span style="font-family: "courier new" , "courier" , monospace;">aws rds describe-db-snapshots --db-snapshot-identifier upgrade-tests-replica-snapshot | grep Status | awk '{print $4}'</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">available</span><br />
<br />
Создаем второй мастер, на основе ранее сделанного снапшота:<br />
<span style="font-family: "courier new" , "courier" , monospace;">aws rds restore-db-instance-from-db-snapshot \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--db-instance-identifier upgrade-tests-2 \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--db-snapshot-identifier upgrade-tests-snapshot \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--db-instance-class db.t2.micro \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--engine postgres</span><br />
<br />
Делать это нужно в той же зоне, что и первый инстанс и в той же Security Group, для того чтобы не гонять трафик через интернет.<br />
<br />
Проверим статус нашего второго инстанса:<br />
<span style="font-family: "courier new" , "courier" , monospace;">PGENDPOINT2=$(aws rds describe-db-instances --db-instance-identifier upgrade-tests-2 | grep Address | awk '{print $4}')</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT2} -p 5432 -U ${PGUSERNAME} postgres -c "select version();"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> PostgreSQL 9.4.15 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-9), 64-bit</span><br />
<br />
Обновим версию PostgreSQL, это занимает довольно много времени:<br />
<span style="font-family: "courier new" , "courier" , monospace;">aws rds modify-db-instance \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--db-instance-identifier upgrade-tests-2 \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--allow-major-version-upgrade \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--engine-version 9.5.12 \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--apply-immediately</span><br />
<br />
После обновления проверим версию PostgreSQL:<br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT2} -p 5432 -U ${PGUSERNAME} postgres -c "select version();"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> PostgreSQL 9.5.12 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-9), 64-bit</span><br />
<br />
Далее нужно настроить мастер-мастер репликацию между ними.<br />
<a href="https://wiki.postgresql.org/wiki/Replication,_Clustering,_and_Connection_Pooling">Тут</a> описаны различные тулзы для этого.<br />
<br />
Для себя я выделил:<br />
<ul style="text-align: left;">
<li>BDR - нужно перекомпиливать PostgreSQL с BDR-плагином</li>
<li>PgCluster - тоже</li>
<li>Rubyrep - проект скорее мертв чем жив</li>
<li>Bucardo - похоже на правду</li>
</ul>
<br />
Включаем реплику на обеих нодах:<br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT} -p 5432 -U ${PGUSERNAME} postgres -c "SET session_replication_role = replica; CREATE EXTENSION plperl;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT2} -p 5432 -U ${PGUSERNAME} postgres -c "SET session_replication_role = replica; CREATE EXTENSION plperl;"</span><br />
<br />
Создаем инстанс в том же регионе и той же Security Group, чтобы общаться с RDS по интранету.<br />
На инстансе устанавливаем <span style="font-family: "courier new" , "courier" , monospace;">bucardo</span>:<br />
<span style="font-family: "courier new" , "courier" , monospace;">apt update && apt install bucardo postgresql-plperl-9.5 -y</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">sed -i 's/ENABLED=0/ENABLED=1/' /etc/default/bucardo</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">mkdir /var/run/bucardo</span><br />
<br />
Устанавливаем пароль для юзера postgres:<br />
<span style="font-family: "courier new" , "courier" , monospace;">sudo -u postgres psql postgres</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">postgres=# \password postgres</span><br />
<br />
Создаем базу:<br />
<span style="font-family: "courier new" , "courier" , monospace;">export PGPASSWORD=bucardo</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h localhost -U postgres postgres -c "CREATE USER bucardo WITH LOGIN SUPERUSER ENCRYPTED PASSWORD 'bucardo';"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h localhost -U postgres postgres -c "CREATE DATABASE bucardo;" </span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">bucardo install</span><br />
<br />
Добавляем оба инстанса в bucardo:<br />
<span style="font-family: "courier new" , "courier" , monospace;">export SOURCE_HOST=upgrade-tests.cge9boeglav8.eu-west-1.rds.amazonaws.com</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export SOURCE_PORT=5432</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export SOURCE_DATABASE=sample</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export SOURCE_USERNAME=admin_rds</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export SOURCE_PASSWORD=admin_rds_pass</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">export DEST_HOST=upgrade-tests-2.cge9boeglav8.eu-west-1.rds.amazonaws.com </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export DEST_PORT=5432 </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export DEST_DATABASE=sample</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export DEST_USERNAME=admin_rds</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export DEST_PASSWORD=admin_rds_pass</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">bucardo add db source_db dbhost=$SOURCE_HOST dbport=$SOURCE_PORT dbname=$SOURCE_DATABASE dbuser=$SOURCE_USERNAME dbpass=$SOURCE_PASSWORD</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">bucardo add db dest_db dbhost=$DEST_HOST dbport=$DEST_PORT dbname=$DEST_DATABASE dbuser=$DEST_USERNAME dbpass=$DEST_PASSWORD</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">bucardo list database</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Database: dest_db Status: active Conn: psql -p 5432 -U admin_rds -d sample -h upgrade-tests-2.cge9boeglav8.eu-west-1.rds.amazonaws.com</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Database: source_db Status: active Conn: psql -p 5432 -U admin_rds -d sample -h upgrade-tests.cge9boeglav8.eu-west-1.rds.amazonaws.com</span><br />
<br />
Добавляем все таблицы и последовательности в группу:<br />
<span style="font-family: "courier new" , "courier" , monospace;">bucardo add table all --db=source_db --herd=sample_herd</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Creating relgroup: sample_herd</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Added table public.city to relgroup sample_herd</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Added table public.country to relgroup sample_herd</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Added table public.countrylanguage to relgroup sample_herd</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">New tables added: 3</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">bucardo list tables</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">1. Table: public.city DB: source_db PK: id (integer)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">2. Table: public.country DB: source_db PK: code (bpchar)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">3. Table: public.countrylanguage DB: source_db PK: countrycode|language (bpchar|text)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">bucardo list herd</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Relgroup: sample_herd DB: source_db Members: public.city, public.country, public.countrylanguage</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">bucardo add sequence all --db=source_db --herd=sample_herd</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Sorry, no sequences were found</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">New sequences added: 0</span><br />
<br />
Создаем группу репликации:<br />
<span style="font-family: "courier new" , "courier" , monospace;">bucardo add dbgroup mydb_servers_group</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">bucardo add dbgroup mydb_servers_group source_db:source</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">bucardo add dbgroup mydb_servers_group dest_db:source</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">bucardo add sync mydb_sync herd=sample_herd dbs=mydb_servers_group</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">bucardo list sync</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Sync "mydb_sync" Relgroup "sample_herd" [Active]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> DB group "mydb_servers_group" dest_db:source source_db:source</span><br />
<br />
После этого можно запускать bucardo:<br />
<span style="font-family: "courier new" , "courier" , monospace;">bucardo start</span><br />
<br />
Тестируем репликацию (CRUD).<br />
<br />
Проверим версии мастеров:<br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT} -p 5432 -U ${PGUSERNAME} postgres -c "select version();"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> PostgreSQL 9.4.15 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-9), 64-bit</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT2} -p 5432 -U ${PGUSERNAME} postgres -c "select version();"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> PostgreSQL 9.5.12 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-9), 64-bit</span><br />
<br />
<b>Insert</b><br />
<b><br /></b>
Пишем в мастер1, проверяем на мастер2:<br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "INSERT INTO city (id, name, countrycode, district, population) VALUES (4080, 'Newtown', 'UKR', 'Kiev', 100);"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT2} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "SELECT * FROM city WHERE id=4080;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> id | name | countrycode | district | population </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">------+------------+-------------+----------+------------</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> 4080 | Newtown | UKR | Kiev | 100</span><br />
<br />
Пишем в мастер2, проверяем на мастер1:<br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT2} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "INSERT INTO city (id, name, countrycode, district, population) VALUES (4081, 'Newcity', 'DEU', 'Berlin', 5);"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "SELECT * FROM city WHERE id=4081;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> id | name | countrycode | district | population </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">------+------------+-------------+----------+------------</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> 4081 | Newcity | DEU | Berlin | 5</span><br />
<br />
<b>Update</b><br />
<br />
Обновляем на мастер1, проверяем на мастер2:<br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "UPDATE city SET population=101 WHERE id=4080;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT2} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "SELECT * FROM city WHERE id=4080;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> id | name | countrycode | district | population </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">------+------------+-------------+----------+------------</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> 4080 | Newtown | UKR | Kiev | 101</span><br />
<br />
Обновляем на мастер2, проверяем на мастер1:<br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT2} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "UPDATE city SET district='Hamburg' WHERE id=4081;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "SELECT * FROM city WHERE id=4081;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> id | name | countrycode | district | population </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">------+------------+-------------+----------+------------</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> 4081 | Newcity | DEU | Hamburg | 5</span><br />
<br />
<b>Delete</b><br />
<br />
Удаляем на мастер1, проверяем на мастер2:<br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "DELETE FROM city WHERE id=4080;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT2} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "SELECT * FROM city WHERE id=4080;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> id | name | countrycode | district | population </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">----+------+-------------+----------+------------</span><br />
<br />
Удаляем на мастер2, проверяем на мастер1:<br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT2} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "DELETE FROM city WHERE id=4081;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "SELECT * FROM city WHERE id=4081;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> id | name | countrycode | district | population </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">------+------------+-------------+----------+------------</span><br />
<br />
Все тесты пройдены успешны.<br />
<br />
Как проверить статус реплики и оставание одного мастера от другого.<br />
<br />
С помощью bucardo:<br />
<span style="font-family: "courier new" , "courier" , monospace;">bucardo delta source_db</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> Total deltas across all targets: 0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> Total deltas for database source_db: 0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">bucardo delta dest_db</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> Total deltas across all targets: 0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> Total deltas for database dest_db: 0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">bucardo status mydb_sync</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">======================================================================</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Last good : Jul 12, 2018 12:47:04 (time to run: 1s)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Rows deleted/inserted : 1 / 1</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Sync name : mydb_sync</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Current state : Good</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Source relgroup/database : sample_herd / source_db</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Tables in sync : 3</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Status : Active</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Check time : None</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Overdue time : 00:00:00</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Expired time : 00:00:00</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Stayalive/Kidsalive : Yes / Yes</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Rebuild index : No</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Autokick : Yes</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Onetimecopy : No</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Post-copy analyze : Yes</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Last error: : </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">======================================================================</span><br />
<br />
С помощью SQL:<br />
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "SELECT pg_last_xlog_receive_location() AS receive, pg_last_xlog_replay_location() AS replay , COALESCE(ROUND(EXTRACT(epoch FROM now() - pg_last_xact_replay_timestamp())),0) AS seconds;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> receive | replay | seconds </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">---------+--------+---------</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> | | 0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">psql -h ${PGENDPOINT2} -p 5432 -U ${PGUSERNAME} sample \</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-c "SELECT pg_last_xlog_receive_location() AS receive, pg_last_xlog_replay_location() AS replay , COALESCE(ROUND(EXTRACT(epoch FROM now() - pg_last_xact_replay_timestamp())),0) AS seconds;"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> receive | replay | seconds </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">---------+--------+---------</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> | | 0</span><br />
Собственно говоря тут все, переключаем приложение на второй мастер, первый мастер тушим, работаем с новой версией PostgreSQL.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-25362912448657274892018-07-01T11:32:00.000+03:002018-10-27T23:39:13.465+03:00Настройка Hashicorp Vault для генерации одноразовых паролей (OTP) для SSH<div dir="ltr" style="text-align: left;" trbidi="on">
Vault — это инструмент для управления секретами от компании Hashicorp известной также другими интересными тулами, такими как Consul, Nomad, Terraform, Vagrant, Packer и прочими.<br />
<br />
Vault удобен тем, что может хранить различные типы секретов, например одноразовые пароли для SSH, доступы к БД, облачным сервисам и прочие key-value варианты. Получается некий аналог keepass/lastpass и google authenticator pam.<br />
<br />
Удобство хашикорповских тулов заключается в том, что они распространяются единым бинарником и легко настраиваются, в том числе и Vault. У Vault неплохая документация, по которой в принципе все понятно.<br />
<br />
В данной заметке я опишу вариант использования One-Time Passwords для логина в SSH, вместо мучений с менеджментом ssh-ключей.<br />
<br />
<a name='more'></a>Как установить Vault описано <a href="https://learn.hashicorp.com/vault/getting-started/install">здесь</a>. Ничего сложного нет, достаточно только лишь скачать бинарник и запустить его.<br />
<br />
В моем случае я разворачивал Vault в амазоне с помощью packer и terraform. Если у кого-то будет похожий кейс, то рекомендую <a href="https://github.com/avantoss/vault-infra">этот</a> репозиторий.<br />
<br />
Окей, Vault мы установили, мы можем залогиниться в веб-интерфейс с помощью рутового токена, создать SSH engine и некоторую роль.<br />
<br />
Для того чтобы можно было генерировать одноразовые токены, на всех машинах, на которые мы хотим соединяться должен быть установлен <a href="https://github.com/hashicorp/vault-ssh-helper">ssh-helper</a>. Опять же, вся установка сводится к скачиванию бинарника и настройке пары конфигов.<br />
<br />
Качаем и устанавливаем helper:<br />
<span style="font-family: "courier new" , "courier" , monospace;">VSH_VERSION=0.1.4</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">SSHD_CONFIG_PATH=/etc/ssh/sshd_config</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">PAMD_CONFIG_PATH=/etc/pam.d/sshd</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">wget https://releases.hashicorp.com/vault-ssh-helper/${VSH_VERSION}/vault-ssh-helper_${VSH_VERSION}_linux_amd64.zip</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">unzip vault-ssh-helper_${VSH_VERSION}_linux_amd64.zip</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">mv vault-ssh-helper /usr/local/bin/</span><br />
<br />
Конфигурим его:<br />
<span style="font-family: "courier new" , "courier" , monospace;">mkdir /etc/vault-helper.d/</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">cat << EOF > /etc/vault-helper.d/config.hcl</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">vault_addr = "https://vault.yourdomain.org:443"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ssh_mount_point = "ssh"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">tls_skip_verify = true</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">allowed_roles = "*"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">allowed_cidr_list="0.0.0.0/0"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">EOF</span><br />
<br />
Также настраиваем конфигурацию PAM:<br />
<span style="font-family: "courier new" , "courier" , monospace;">sed -i -e 's/^@include common-auth/#@include common-auth/g' ${PAMD_CONFIG_PATH}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">echo "auth requisite pam_exec.so quiet expose_authtok log=/tmp/vaultssh.log /usr/local/bin/vault-ssh-helper -config=/etc/vault-helper.d/config.hcl" | tee -a ${PAMD_CONFIG_PATH}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">echo "auth optional pam_unix.so not_set_pass use_first_pass nodelay" | tee -a ${PAMD_CONFIG_PATH}</span><br />
<br />
И конфигурацию SSH:<br />
<span style="font-family: "courier new" , "courier" , monospace;">sed -i -e 's/ChallengeResponseAuthentication no/ChallengeResponseAuthentication yes/g' ${SSHD_CONFIG_PATH}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">sed -i -e 's/UsePAM no/UsePAM yes/g' ${SSHD_CONFIG_PATH}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">sed -i -e 's/PasswordAuthentication yes/PasswordAuthentication no/g' ${SSHD_CONFIG_PATH}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">systemctl restart sshd</span><br />
<br />
Ноду на которую мы будем соединяться мы настроили, далее снова идем на ноду с Vault и включаем engine SSH:<br />
<span style="font-family: "courier new" , "courier" , monospace;">vault secrets enable ssh</span><br />
<br />
Создаем роль:<br />
<span style="font-family: "courier new" , "courier" , monospace;">vault write ssh/roles/otp_key_role key_type=otp default_user=ubuntu cidr_list=0.0.0.0/0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Success! Data written to: ssh/roles/otp_key_role</span><br />
<br />
И генерируем доступы:<br />
<span style="font-family: "courier new" , "courier" , monospace;">vault write ssh/creds/otp_key_role ip=192.168.10.12</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Key Value</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">--- -----</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">lease_id ssh/creds/otp_key_role/edc499e3-c100-405f-203b-c775d29c0233</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">lease_duration 192h</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">lease_renewable false</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ip 192.168.10.12</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">key ce307d33-84d8-0794-f284-b8b3c8e43699</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">key_type otp</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">port 22</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">username ubuntu</span><br />
<br />
Пробуем соединиться с любой машины с этими доступами:<br />
<span style="font-family: "courier new" , "courier" , monospace;">ssh ubuntu@192.168.10.12</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Password: ce307d33-84d8-0794-f284-b8b3c8e43699</span><br />
<br />
Если же попробуете с этими доступами соединиться повторно, то ничего не выйдет, так как они одноразовые.<br />
Генерировать доступы можно и через веб-интерфейс, нужно лишь в настройках включить вход по LDAP или GitHub например, настроить полиси для юзеров (например определенному юзеру разрешено заходить только на разрешенные ноды).</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-19278669805487233972018-06-16T10:48:00.000+03:002018-06-16T15:11:17.874+03:00Разница между su, su -, sudo -i, sudo -s<div dir="ltr" style="text-align: left;" trbidi="on">
Промучавшись полдня с настройкой Hashicorp Vault до меня никак не могло дойти, что я делаю не так, ведь по сути ничего супер сложного там нет, однако я сталкивался с множеством ошибок при попытке запуска Vault-сервера.<br />
<br />
Для получения прав рута на сервере я обычно использую команду <span style="font-family: "courier new" , "courier" , monospace;">sudo -s</span>, почему именно ее — точно не вспомню, просто исторически сложилось и каких-либо проблем по этому поводу не испытывал.<br />
<br />
Как оказалось, моя ошибка при настройке Vault была именно в том, что рута я получал именно такой командой.<br />
Вот что пишут в мане:<br />
<span style="font-family: "courier new" , "courier" , monospace;">-s, --shell Run the shell specified by the SHELL environment variable if it is set or the shell specified by the invoking user's password database entry. If a command is specified, it is passed to the shell for execution via the shell's -c option. If no command is specified, an interactive shell is executed.</span><br />
<div>
<br /></div>
<div>
Команда запускает shell из-под рута без смены директории, при этом не импортируются переменные окружения, которые прописаны например в <span style="font-family: "courier new" , "courier" , monospace;">.bash_profile</span> или <span style="font-family: "courier new" , "courier" , monospace;">.login</span>.</div>
<div>
<br /></div>
<div>
В случае <span style="font-family: "courier new" , "courier" , monospace;">sudo -i</span> совсем другая история:</div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">-i, --login Run the shell specified by the target user's password database entry as a login shell. This means that login-specific resource files such as .profile or .login will be read by the shell. If a command is specified, it is passed to the shell for execution via the shell's -c option. If no command is specified, an interactive shell is executed. sudo attempts to change to that user's home directory before running the shell. The command is run with an environment similar to the one a user would receive at log in. The Command environment section in the sudoers(5) manual documents how the -i option affects the environment in which a command is run when the sudoers policy is in use.</span></div>
</div>
<div>
<br /></div>
<div>
Тут запускается shell со сменой директории пользователя и импортом переменных окружения.</div>
<div>
<br /></div>
<div>
В случае <span style="font-family: Courier New, Courier, monospace;">su</span> и <span style="font-family: Courier New, Courier, monospace;">su -</span> тоже есть разница.</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">su -</span> в этом случае сначала переключается пользователь, а затем вызывается shell, то есть очищая все переменные окружения и запуская чистую сессию рута.</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">su</span> не очищает переменные окружения, а просто переключает пользователя оставляя переменные окружения старого пользователя.</div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-35206798544383847572018-06-11T19:35:00.004+03:002018-06-11T19:35:47.268+03:00Создание пользователя с правами администратора в RabbitMQ<div dir="ltr" style="text-align: left;" trbidi="on">
<span style="font-family: Courier New, Courier, monospace;"># rabbitmqctl add_user rabbitadmin password</span><br />
<span style="font-family: Courier New, Courier, monospace;"># rabbitmqctl set_user_tags rabbitadmin administrator</span><br />
<span style="font-family: Courier New, Courier, monospace;"># rabbitmqctl set_permissions -p / rabbitadmin ".*" ".*" ".*"</span></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-23358853219807061222018-05-14T13:52:00.001+03:002018-06-02T16:26:45.493+03:00Вопросы на собеседовании на позицию DevOps-инженера<div dir="ltr" style="text-align: left;" trbidi="on">
Опишу тут некоторые вопросы, которые мне задавали на эту позицию.<br />
Я около месяца проходил собеседования в компании из России, Украины, Европы и некоторые из вопросов я запомнил. Конечно, по большей части вопросы задавали конкретно по моему опыту работы, который я описал в резюме, однако некоторые из них повторялись очень часто и их стоит выделить.<br />
<br />
<a name='more'></a>На всех собеседованиях на данную позицию в первую очередь проверяют уровень английского. Для каждой компании этот уровень разный, для некоторых достаточно того, чтобы ты понимал документацию на английском и мог в письменном виде как-то коммуницировать, для некоторых важен разговорный английский, так как либо общение с заказчиком, либо непосредственно с командой идет на этом языке.<br />
<br />
При собеседовании с европейскими компаниями как правило достаточно знать английский на уровне Intermediate/Upper-Intermediate и бегло говорить на нем (понимать что говорит интервьюер и выразить свои мысли устно). Местные языки обычно не спрашивают, например при собеседовании в немецкие компании, знание немецкого не является обязательным.<br />
<br />
Несколько пометок которые я для себя сделал после собеседований с европейцами:<br />
1. Отвечать кратко и не говорить лишней информации<br />
2. Улыбаться<br />
3. Иметь веселую интонацию в голосе<br />
4. Желательно узнать немного о компании в которую собеседуетесь<br />
5. Быть готовым ответить на вопросы: сколько хотите зарабатывать, сколько времени понадобится на релокейт, почему решили переехать, где вы видите себя через N лет, имеется ли опыт работы с иностранным заказчиком<br />
<br />
На английском языке обычно просят рассказать о себе, о своем опыте работы, о зарплатных ожиданиях, почему тебе нравится именно эта позиция и так далее.<br />
<br />
Непосредственно вопросы технического характера:<br />
— Что такое Load Average, SWAP, inode?<br />
— Опишите модель OSI и все ее уровни?<br />
— Чем отличается TCP от UDP, как устанавливается соединение TCP?<br />
— Когда нужно использовать SWAP, а когда нет?<br />
— Чем отличается <span style="font-family: "courier new" , "courier" , monospace;">git pull</span> от <span style="font-family: "courier new" , "courier" , monospace;">git fetch</span>?<br />
— Чем отличается транзакция от запроса, в контексте БД?<br />
— Как починить <span style="font-family: "courier new" , "courier" , monospace;">chmod -x /bin/chmod</span>?<br />
— Что такое DevOps, Agile?<br />
— С какими методологиями разработки ПО работал? Что знаешь о Scrum, Kanban и т.д?<br />
— Чем виртуалки отличаются от контейнеров?<br />
— Клиенты жалуются на то, что веб-сервис стал медленно работать, как бы ты последовательно докапывался до проблемы? Как обнаружить bottleneck?<br />
— Чем отличаются реляционные БД от нереляционных и key-value? С какими из них работал, как бы ты организовывал разгрузку баз, репликации, миграции, бекапы?<br />
— Что такое балансировщик? Какие типы балансировки при деплое знаешь? Что такое blue-green deployment, канареечные релизы?<br />
— Как бы ты организовал поднятие инфраструктуры в облаке, в случае если отвалилась целая зона или регион?<br />
— Как налету мигрировать работающую базу из одного региона в другую?<br />
— Как бы ты строил ту или иную архитектуру проекта?<br />
— Работал ли с облаками, AWS, GCP, Azure, OpenStack?<br />
— Что представляет собой докер-контейнер? Из каких двух базовых вещей состоят контейнеры (имеется ввиду namespaces и cgroups)?<br />
— Какие инструменты оркестрации контейнеров использовал? Для чего нужен Kubernetes, Nomad, Swarm, Compose?<br />
— Есть ли опыт работы со стеком ELK, со стеком ПО от Hashicorp (Vault, Consul, Nomad, Terraform и т.д)?<br />
— С какими системами мониторинга работал? Есть опыт работы с Prometheus?<br />
— С какими CI-системами работал? В чем отличия Jenkins от TeamCity и других аналогичных систем?<br />
— Что такое Continuous Integration/Delivery/Deployment и чем они друг от друга отличаются?<br />
— Есть ли опыт внедрения CI/CD в инфраструктуру java-приложений (ant/maven/gradle)?<br />
— С какими системами управления конфигурациями работал (Ansible/Puppet/Chef и т.д)? Почему именно с ними, в чем между ними разница?<br />
— Как в access-логе Nginx посмотреть самые активные IP-адреса за последние сутки с помощью BASH?<br />
— Как отсортировать массив в Python? Написать код в реальном времени.<br />
<br />
И напоследок.<br />
Есть такой скрипт на баше, какие ошибки ты в нем видишь?<br />
<span style="font-family: "courier new" , "courier" , monospace;">#!/usr/bin/env bash</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">include <stdio.h></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">include <math.h></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">trigger_counter = 1</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">data_dir="/var/test/dash"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">curl --silent -h "Content-Type: application/json" "https://bitbucket.org/testproj/python/test.tar.gz" -o /test.tar.gz</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">tar -xf /test.tar.gz -C /opt/</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">uwsgi -d --ini /opt/main.py</span></div>
Unknownnoreply@blogger.com6tag:blogger.com,1999:blog-988974329398903021.post-39671640222478675512018-05-05T09:15:00.000+03:002018-05-05T09:15:02.112+03:00Работа с памятью в Linux<div dir="ltr" style="text-align: left;" trbidi="on">
Одной из наиболее важных и базовых подсистем в любой операционной системе является подсистема работы с оперативной памятью (MMU — Memory Management Unit). Конструкция данной подсистемы является очень сложной, поэтому разработчикам программного обеспечения должны очень хорошо понимать общее устройство как ядра Linux, так и то, как функционируют подобные подсистемы, к счастью все это отлично документировано в исходных кодах ядра.<div>
<br /><a name='more'></a>Когда мы говорим о памяти, чаще всего мы имеем в виду физическую память. К примеру когда вы приобретаете себе новый компьютер или ноутбук, то вы обращаете внимание именно на физическую память.<br /><br />Операционная система занимается задачей распределения доступной памяти для приложений и является некой абстракцией для приложений, так как было бы неудобно каждому приложению обращаться напрямую к адресам памяти. В свою очередь операционная система оперирует понятиями страницы памяти, так как работать напрямую с каждым адресом не удобно. По умолчанию размер страницы в Linux равен 4KB, это сделано из-за того, что очень сложно обращаться за каждым байтом к памяти.<br />Процесс операционной системы работает с виртуальной памятью, это та память, которая выделяется процессу операционной системой. <br />Операционная система следит за тем, чтобы выделенные для одного процесса страницы памяти не пересекались со страницами памяти которые были выделены для другого процесса.</div>
<div>
<br />В отличие от физической памяти, которую можно расширить только на аппаратном уровне, виртуальная память является совокупностью физической памяти и swap.<br />SWAP является механизмом управления памятью, при котором отдельные фрагменты памяти (как правило неактивные или малоактивные) могут быть перемещены из RAM на диск. Поэтому можно утверждать что размер виртуальной памяти можно неограниченно расширять с помощью дисков, однако стоит учесть то, что доступ к фрагментам памяти расположенных на диске будет значительно медленнее, чем непосредственно к RAM.<br /><br />Как уже упоминалось ранее, процессы получают доступ к памяти, которой управляет операционная система, таким образом процесс работает только с выделенным ему объемом памяти и не отвечает за ее контроль. <br />Как правило, разработчики которые пишут приложения на высокоуровневых языках программирования не беспокоятся о работе памяти, так как за них об этом уже позаботились разработчики языка программирования или библиотеки.<br /><br />Память можно разделить на две большие группы: файловая и анонимная.<br />Какой-либо файл или часть файловой системы соответствует понятию файловой памяти. Именно в файлах располагается исполняемый код приложения. С помощью системного вызова <span style="font-family: Courier New, Courier, monospace;">mmap</span> приложение обращается к виртуальному адресному пространству память.<br /><br />Если же памяти не соответствует никакой файл, то такая память называется анонимной. Для выделения анонимной памяти используется функция <span style="font-family: Courier New, Courier, monospace;">malloc</span>.<br /><br />При использовании файловой памяти, операционная система может сопоставлять виртуальные адреса разных процессов, которые работают с одними и теми же файлами, таким образом экономится физическая память, за счет того что процессы работают с одним и тем же виртуальным адресом.<br /><br />В случаях, когда память невозможно вытеснить для работы процесса используется OOM killer. Данных механизм выбирает процесс (как правило, самый объемный) и освобождает его память для работы других процессов, по умолчанию он включен в Linux. Если же отключить OOM killer, то в случае заполнения памяти остается только физически перезагрузить компьютер.<br /><br />Для изоляции процессов в рамках определенной памяти существует механизм cgroups, который разделяет процессы на логические группы и выделяет им назначенный объем оперативной памяти. Появление технологии cgroups в ядре Linux сыграло большую роль в распространении контейнерных технологий, таких как Docker и OpenVZ.<br /><br />Ядро Linux также умеет работать с многопроцессорными системами (NUMA — Non-Uniform Memory Access). То есть в случае если процессор физические располагается ближе к оперативной памяти, то в первую очередь он будет обращаться именно к этой части RAM.<br /><br />Рассмотрим типичный вывод системной информации об оперативной памяти в Linux:<br /><span style="font-family: Courier New, Courier, monospace;">$ sudo cat /proc/meminfo <br />MemTotal: 3789684 kB<br />MemFree: 1765616 kB<br />MemAvailable: 3051416 kB<br />Buffers: 134112 kB<br />Cached: 990372 kB<br />SwapCached: 0 kB<br />Active: 1190556 kB<br />Inactive: 579688 kB<br />Active(anon): 646244 kB<br />Inactive(anon): 7252 kB<br />Active(file): 544312 kB<br />Inactive(file): 572436 kB<br />Unevictable: 0 kB<br />Mlocked: 0 kB<br />SwapTotal: 0 kB<br />SwapFree: 0 kB<br />Dirty: 1936 kB<br />Writeback: 0 kB<br />AnonPages: 645756 kB<br />Mapped: 141264 kB<br />Shmem: 7740 kB<br />Slab: 214240 kB<br />SReclaimable: 197816 kB<br />SUnreclaim: 16424 kB<br />KernelStack: 2960 kB<br />PageTables: 17536 kB<br />NFS_Unstable: 0 kB<br />Bounce: 0 kB<br />WritebackTmp: 0 kB<br />CommitLimit: 1894840 kB<br />Committed_AS: 1601240 kB<br />VmallocTotal: 34359738367 kB<br />VmallocUsed: 9668 kB<br />VmallocChunk: 34359720912 kB<br />HardwareCorrupted: 0 kB<br />AnonHugePages: 0 kB<br />HugePages_Total: 0<br />HugePages_Free: 0<br />HugePages_Rsvd: 0<br />HugePages_Surp: 0<br />Hugepagesize: 2048 kB<br />DirectMap4k: 79820 kB<br />DirectMap2M: 2803712 kB<br />DirectMap1G: 1048576 kB</span><br /><br /><span style="font-family: Courier New, Courier, monospace;">MemTotal</span> отображает доступный объем оперативной памяти<br /><span style="font-family: Courier New, Courier, monospace;">MemFree</span> указывает объем неиспользуемый объем оперативной памяти<br /><span style="font-family: Courier New, Courier, monospace;">Buffers</span> — область памяти, в которой хранятся данные ожидающие записи на диск, буфер позволяет процессам продолжать работу не дожидаясь физической записи на диск<br /><span style="font-family: Courier New, Courier, monospace;">Cached</span> отображает объем памяти занятый под кэш (файлы, каталоги, файлы блочных устройств и т.д)<br /><span style="font-family: Courier New, Courier, monospace;">SwapCached</span> указывает на объем памяти, который был помещен в swap, а затем перенесен обратно в RAM, при этом данные все еще присутствуют в swap<br /><span style="font-family: Courier New, Courier, monospace;">Active</span> отображает объем памяти, который наиболее часто используется страницами памяти, данные страницы памяти освобождаются довольно редко<br /><span style="font-family: Courier New, Courier, monospace;">Inactive</span> в свою очередь не используются в данный момент, данные страницы являются первоочередными кандидатами для выгрузки в swap в случае необходимости<br /><span style="font-family: Courier New, Courier, monospace;">Unevictable</span> -- страницы памяти, которые по каким-либо причинам не могут быть помещены в swap<br /><span style="font-family: Courier New, Courier, monospace;">Mlocked</span> отображает память, внесенную в адресное пространство с помощью системного вызова <span style="font-family: inherit;">mlock</span><br /><span style="font-family: Courier New, Courier, monospace;">SwapTotal</span> и <span style="font-family: Courier New, Courier, monospace;">SwapFree</span> — общий объем и свободный объем swap<br /><span style="font-family: Courier New, Courier, monospace;">Dirty</span> — измененные страницы памяти, которые все еще находятся в RAM, но еще не сброшены на диск<br /><span style="font-family: Courier New, Courier, monospace;">Writeback</span> это память которая в данный момент сбрасывается на диск<br /><span style="font-family: Courier New, Courier, monospace;">AnonPages</span> — объем анонимной памяти<br /><span style="font-family: Courier New, Courier, monospace;">Mapped</span> отображает объем памяти, внесенный в адресное пространство с помощью mmap<br /><span style="font-family: Courier New, Courier, monospace;">Slab</span> — объем памяти выделенный под структуры ядра небольшого объема<br /><span style="font-family: Courier New, Courier, monospace;">PageTables</span> — память выделенная под страничную таблицу<br /><span style="font-family: Courier New, Courier, monospace;">NFS_Unstable</span> указывает на объем памяти используемый для передачи данных по NFS v3+<br /><span style="font-family: Courier New, Courier, monospace;">Bounce</span> — память используемая блочным устройством<br /><span style="font-family: Courier New, Courier, monospace;">CommitLimit</span> — based on the overcommit ratio (vm.overcommit_ratio), this is the total amount of memory currently available to be allocated on the system. This limit is only adhered to if strict overcommit accounting is enabled (mode 2 in vm.overcommit_memory)<br /><span style="font-family: Courier New, Courier, monospace;">Committed_AS</span> — the amount of memory presently allocated on the system. The committed memory is a sum of all of the memory which has been allocated by processes, even if it has not been "used" by them as of yet<br /><span style="font-family: Courier New, Courier, monospace;">VmallocTotal</span> — виртуальное пространство, доступное для vmalloc<br /><span style="font-family: Courier New, Courier, monospace;">VmallocUsed</span> — объем использованного пространства vmalloc<br /><span style="font-family: Courier New, Courier, monospace;">VmallocChunk</span> — наибольший свободный блок внутри vmalloc<br /><span style="font-family: Courier New, Courier, monospace;">HugePages_Total</span> — количество huge страниц выделенных ядром<br /><span style="font-family: Courier New, Courier, monospace;">HugePages_Free</span> — количество huge страниц, которые не выделяются<br /><span style="font-family: Courier New, Courier, monospace;">HugePages_Rsvd</span> — количество huge страниц, которые должны были выделиться из пула, но еще этого не сделали<br /><span style="font-family: Courier New, Courier, monospace;">Hugepagesize</span> — количество huge страниц<br /><span style="font-family: Courier New, Courier, monospace;">DirectMap1G</span> — память выделенная под huge страницы размером 1GB<br /><br />RHEL 6/7 only:<br /><span style="font-family: Courier New, Courier, monospace;">Shmem</span> указывает объем виртуальной памяти, используемой несколькими процессами<br /><span style="font-family: Courier New, Courier, monospace;">SReclaimable</span> является частью памяти которая может быть reclaimed<br /><span style="font-family: Courier New, Courier, monospace;">SUnreclaim</span> — память которая не может быть reclaimed<br /><span style="font-family: Courier New, Courier, monospace;">KernelStack</span> — память используемая стеком ядра<br /><span style="font-family: Courier New, Courier, monospace;">WritebackTmp</span> объем памяти используемой FUSE для временной записи буферов<br /><span style="font-family: Courier New, Courier, monospace;">HardwareCorrupted</span> является объемом памяти, которую ядро обозначил нерабочей<br /><span style="font-family: Courier New, Courier, monospace;">AnonHugePages</span> — объем памяти занимаемой огромными (huge) анонимными страницами<br /><span style="font-family: Courier New, Courier, monospace;">HugePages_Surp</span> — количество huge страниц в пуле, значение которых выше vm.nr_hugepages<br /><span style="font-family: Courier New, Courier, monospace;">DirectMap4k</span> — память выделенная под стандартные страницы размером 4KB<br /><span style="font-family: Courier New, Courier, monospace;">DirectMap2M</span> — память выделенная под huge страницы размером 2MB<br /><br />С помощью таких утилит как <span style="font-family: Courier New, Courier, monospace;">ps</span>, <span style="font-family: Courier New, Courier, monospace;">top</span>, <span style="font-family: Courier New, Courier, monospace;">atop</span>, <span style="font-family: Courier New, Courier, monospace;">htop</span> и прочих можно проанализировать потребление памяти каждым процессом в системе.<br />Очистку кэша памяти можно произвести командой:<br /><span style="font-family: Courier New, Courier, monospace;"># free && sync && echo 3 > /proc/sys/vm/drop_caches && free</span></div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-32341174217115648652018-05-01T09:19:00.001+03:002022-04-16T14:33:33.080+03:00Как я могу узнать свой внешний IP-адрес<div dir="ltr" style="text-align: left;" trbidi="on">
Для идентификации компьютеров сети используются адреса. На уровне данных используются MAC-адреса, каждый MAC-адрес является уникальным и устанавливается производителем на этапе производства. Формат MAC-адреса представляет собой набор из шести октетов в шестнадцатиричном формате, примером MAC-адреса является <span style="font-family: "courier new" , "courier" , monospace;">20:89:84:59:0B:6A</span><br />
<br />
Хоть MAC-адрес и является уникальным, его можно изменить программно во многих случаях, в других же случаях это можно сделать с помощью программатора. Изменение MAC-адреса может привести к неожиданным последствиям, в случае использования дублирующихся в одной подсети.<br />
<br />
<a name='more'></a>Для идентификации адресов на более высоких уровнях используются IP-адреса, долгое время стандартом является протокол IP версии 4, на смену которому приходит протокол версии 6.<br />
<br />
У каждого компьютера может существовать несколько IP-адресов, чаще всего это адрес <span style="font-family: "courier new" , "courier" , monospace;">127.0.0.1</span>, который используется для работы сети в пределах одного устройства (localhost). Внутренний IP-адрес может иметь вид <span style="font-family: "courier new" , "courier" , monospace;">192.168.0.2</span> или <span style="font-family: "courier new" , "courier" , monospace;">10.0.0.2</span>, как правило такие адреса необходимы для взаимодействия в пределах внутренней сети (intranet). И напоследок внешний IP-адрес, например <span style="font-family: "courier new" , "courier" , monospace;">8.8.8.8</span>, который доступен всем во внешней сети.<br />
<br />
К сожалению количество адресов IPv4 очень ограничено и подходит к концу, поэтому для экономии внешних адресов используются такие технологии как NAT, которые позволяют использовать множество внутренних немаршрутизируемых для интернета адресов для одного внешнего адреса. То есть получается ситуация при которой, множество компьютеров внутренней сети могут выходить в сеть, но компьютеры из интернета не могут получить доступ к внутренней сети без специальных настроек на маршрутизаторе, таких как Port Forwarding например.<br />
<br />
В Linux существует утилита ip, для управления сетевыми интерфейсами.<br />
Посмотрим адрес loopback-интерфейса (lo):<br />
<span style="font-family: "courier new" , "courier" , monospace;">$ ip a show lo | grep "inet "<br /> inet 127.0.0.1/8 scope host lo</span><br />
<br />
И адрес компьютера во внутренней сети (компьютер находится за маршрутизатором):<br />
<span style="font-family: "courier new" , "courier" , monospace;">$ ip a show eth0 | grep "inet "<br /> inet 192.168.0.103/24 brd 192.168.0.255 scope global dynamic eth0</span><br />
<br />
Но как узнать свой внешний IP-адрес, тот самый адрес, с помощью которого мы можем идентифицироваться в сети?<br />
В некоторых случаях это необходимо для того чтобы получить доступ к серверу через интернет, например через SSH, или для того чтобы добавить корректные записи DNS.<br />
<br />
Существует множество способов узнать свой внешний IP-адрес, в случае сложной топологии сети, например когда вы используете NAT. С помощью таких сервисов как <a href="https://myexternalip.com/">myexternalip.com</a> или <a href="http://showip.net/">showip.net</a> можно узнать свой внешний адрес через браузер, однако если нужно узнать адрес в автоматическом режиме, то каждый раз ходить по ссылкам в браузере неудобно.<br />
<br />
Для этого можно воспользоваться специальными сервисами, которые передают данные по HTTP(S), FTP, Telnet либо с помощью DNS.<br />
Узнаем внешний адрес с помощью DNS:<br />
<span style="font-family: "courier new" , "courier" , monospace;">$ dig +short myip.opendns.com @resolver1.opendns.com<br />83.143.203.86<br /><br />$ nslookup . ifcfg.me | grep "Address: "<br />Address: 83.143.203.86</span><br />
<br />
FTP / Telnet:<br />
<span style="font-family: "courier new" , "courier" , monospace;">$ echo close | ftp 4.ifcfg.me | awk '{print $4; exit}'<br />$ nc 4.ifcfg.me 23 | grep IPv4 | cut -d' ' -f4<br />$ telnet 4.ifcfg.me 23 | grep IPv4 | cut -d' ' -f4<br />$ netcat icanhazip.com 80 <<< $'GET / HTTP/1.1\nHost: icanhazip.com\n\n' | tail -n1</span><br />
<br />
HTTP(S):<br />
<span style="font-family: "courier new" , "courier" , monospace;">$ curl http://canhazip.com<br />$ curl http://whatismyip.akamai.com/<br />$ curl https://4.ifcfg.me/<br />$ curl http://checkip.amazonaws.com<br />$ curl -s http://whatismijnip.nl | awk '{print $5}'<br />$ curl -s icanhazip.com<br />$ curl ident.me<br />$ curl ipecho.net/plain<br />$ curl wgetip.com<br />$ curl ip.tyk.nu<br />$ curl bot.whatismyipaddress.com<br />$ wget -q -O - checkip.dyndns.org | sed -e 's/[^[:digit:]\|.]//g'</span><br />
<br />
Использование подобных конструкций может пригодиться в скриптах или в повседневной работе, в случае если данный адрес является динамическим.<br />
<br />
Можно создать алиас, с помощью которого можно узнать свой внешний адрес, не прописывая длинных команд:<br />
<span style="font-family: "courier new" , "courier" , monospace;">$ alias wanip='dig +short myip.opendns.com @resolver1.opendns.com'<br />$ echo "alias wanip='dig +short myip.opendns.com @resolver1.opendns.com'" | tee -a ~/.bashrc<br />$ wanip<br />83.143.203.86</span></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-988974329398903021.post-85433835244269716122018-04-20T23:41:00.000+03:002018-04-20T23:41:28.025+03:00Быстрая установка стека ELK (Elasticsearch+Logstash+Kibana) на Debian 9<div dir="ltr" style="text-align: left;" trbidi="on">
Ставим все необходимые пакеты:<br />
<span style="font-family: Courier New, Courier, monospace;"># apt install -y openjdk-9-jre apt-transport-https</span><br />
<span style="font-family: Courier New, Courier, monospace;"># wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | apt-key add -</span><br />
<span style="font-family: Courier New, Courier, monospace;"># echo "deb https://artifacts.elastic.co/packages/6.x/apt stable main" | tee -a /etc/apt/sources.list.d/elastic-6.x.list</span><br />
<span style="font-family: Courier New, Courier, monospace;"># apt update && apt install elasticsearch kibana logstash packetbeat metricbeat filebeat heartbeat -y</span><br />
<br />
Запускаем elasticsearch на локалхосте:<br />
<span style="font-family: Courier New, Courier, monospace;"># vim /etc/elasticsearch/elasticsearch.yml</span><br />
<span style="font-family: Courier New, Courier, monospace;">network.host: 127.0.0.1</span><br />
<br />
Прописываем конфиг logstash:<br />
<span style="font-family: Courier New, Courier, monospace;"># vim /etc/logstash/conf.d/10-syslog.conf</span><br />
<span style="font-family: Courier New, Courier, monospace;">input {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> file {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> type => "syslog"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> path => [ "/var/log/messages", "/var/log/*.log" ]</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;">output {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> stdout { </span><br />
<span style="font-family: Courier New, Courier, monospace;"> codec => rubydebug</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> elasticsearch {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> hosts => "localhost"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
Запускаем сервисы:<br />
<span style="font-family: Courier New, Courier, monospace;"># systemctl enable elasticsearch kibana logstash filebeat packetbeat metricbeat heartbeat</span><br />
<span style="font-family: Courier New, Courier, monospace;"># systemctl start elasticsearch kibana logstash filebeat packetbeat metricbeat heartbeat</span><br />
<br />
Идем по адресу: <span style="font-family: Courier New, Courier, monospace;">http://localhost:5601</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-IQL4Tfm951M/WtpQCAeiL5I/AAAAAAAABuc/2puOjCSSDpg6kPbiD4oBNy2qzVYdGNBywCLcBGAs/s1600/elk.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1058" data-original-width="1600" height="263" src="https://4.bp.blogspot.com/-IQL4Tfm951M/WtpQCAeiL5I/AAAAAAAABuc/2puOjCSSDpg6kPbiD4oBNy2qzVYdGNBywCLcBGAs/s400/elk.png" width="400" /></a></div>
</div>
Unknownnoreply@blogger.com0