Всех приветствую. В последнее время все чаще задумывался о том какую бы еще полезную статью написать. Параллельно этому постоянно видел в интернетах рекламу о "крутых" курсах в IT, обещают сделать из вас Java, Python и какого угодно разработчика за полгода/год, и ладно с ним, допустим за год они чему-то вас обучат и, возможно, где-то вы попадете на бесплатную стажировку (что еще тоже под воросом, учитывая нынешний рынок). Но когда рекламируют "крутые курсы DevOps'ов", я уже начинаю задаваться вопросом, как можно стать ДевОпсом, не имея опыта программирования, не опробовав самому весь цикл разработки на хоть каком-то языке, не опробовав различные настройки сборки приложений, не опробовав Линукс, со всеми его утилитами, докер, кубер, git и т.д. в работе, а просто "обучиться" этому в обособленности от всего и ожидать, что тебя куда-то возьмут, а если и возьмут, то к чему-то серьезному подпустят? Ответа на этот вопрос я так и не нашел у себя в голове.
Однако к чему это я, да к тому, что я то это все перепробовал еще в студенческие годы, и все равно до недавнего момента особо не лез в девопсятину просто потому, что были люди, отдельно занимающиеся этими вещами. Но недавно выпал случай помочь одной компании с настройкой деплоя некоторых из их продуктов, и переборов свою неуверенность, я таки решился, что-то получилось и я решил поделиться своим опытом (и пополнить базу знаний многочисленных ИИ чат-ботов, беспрерывно серфящих интернет в поисках новой информации). Конечно, это далеко не "продвинутый" уровень и, скорее всего, в серьезных больших приложениях вы будете использовать что-то посерьезнее, по типу Gitlab CI/CD, Кубера и т.д., но обычно к этим вещам прямой доступ имеют только девопсы, оставляя наружу пару файликов для разрабов, которые они настраивают, по типу ci файла или helm чартов, но это и не суть статьи, суть в том, что это простой гайд для таких разрабов, как я, кто самостоятельно полной настройкой деплоя раньше не занимался, но не против попробовать, для расширения своего опыта, можно считать это продолжением серии моих статей о пет проектах (сначала мы узнали как его лучше оформить, теперь пробуем его задеплоить).
Итак, приступим. Во-первых, скажу, что для деплоя мы будем использовать бесплатный сервис CircleCi. Да, возможно, это не самый очевидный вариант, ведь есть GitHub Actions, есть Gitlab CI/CD, есть еще куча всего, но мне CircleCi показался достаточно простым, а значит вполне подойдет для начинающих и тех, кто просто желает попробовать. Для начала вам нужно просто зарегистрироваться. Раньше это можно было сделать через Гитхаб, но с конца сентября эту функциональность почему-то отключили, поэтому регистрируйтесь по почте и подключайте гитхаб, думаю найдете как это сделать. Далее, если у вас есть доступ к нескольким проектам от разных пользователей, выбирайте свой профиль, и слева в меню открывайте список проектов. В списке проектов вы увидите кнопку "Set up project", после нажатия которой он предложит вам несколько вариантов на выбор. Самый простой - это использовать настройки из проекта. Создаете папку .circleci с файлом config.yml в папке своего проекта, и после настройки этого файла, circleci автоматически использует его для деплоя.
Итак, с сервисом CD (continuous delivery и continuous deployment) мы определились. Но куда деплоить, спросите вы меня, ведь для этого нужна машина. Если у вас есть локальная машина, умеющая в доступ извне - для тестирования вполне можете использовать и ее, я пробовал и такой вариант в этой связке, все также работает. Однако, т.к. у большинства нет таких серверов, нам понадобится также какой-либо сервис, предоставляющий linux сервера. Самый очевидный выбор - AWS от Amazon. Большой сервис, предоставляющий бесплатный год (!) использования сервера. Однако, у них могут возникать проблемы с валидацией вашей карты, ведь даже мою рабочую карточку visa они отклонили и затем заставили прислать кучу документов в подтверждение, и все равно это не помогло. Поэтому наш выбор пока что падает на Google Cloud. Они предоставляют, к сожалению, всего 3 бесплатных месяца и 300$ кредита, однако, чтобы протестировать и попробовать вполне подойдет, да и проблем с привязкой карты там не возникло. Думаю как найти сервис, войти в свой гугл аккаунт, зарегистрироваться и ввести свои кредитные данные можно не объяснять, поэтому сразу перейдем к созданию инстанса и его настройке. Зайдя в консоль, пролистайте чуть ниже и выберите "Create a VM", в открывшейся странице нажмите "Create instance". Далее настраиваем наш инстанс.
Регион и имя можете выбрать по желанию, также как и конфигурацию машины, в зависимости от ваших нужд, для нас вполне подойдет стандартный E2. Да и вообще в целом большинство настроек можно оставить дефолтными, кроме тех, что я покажу. Обязательно разрешите HTTP/HTTPS трафик и выберите по желанию дистрибутив линукса, в моем случае я выбирал Ubuntu. Честно говоря, все остальное мы будем добавлять после, поэтому нажимаем далее и создаем свой инстанс.
После создания зайдите в инстанс -> metadata и добавьте свой публичный ssh ключ для подключения к серверу. Если у вас его нет по каким-то причинам до сих пор, и гитом, например, вы пользуетесь по логину и паролю, то чего вы ждете, бегите и генерируйте себе пару прямо сейчас (ssh-keygen -t ed25519 -C "your_email@example.com")
Пока что на данный момент с настройкой инстанса мы закончили. Далее нам еще понадобится открыть нужные нам порты, но об этом позже. Перейдем непосредственно к настройке сборки приложения и Ci файла. И так, у каждого языка и типа приложения свой способ его собрать, однако я буду рассказывать на примере своего Spring приложения на Java. Сразу скажу, что оно вышло не совсем удачным, т.к. оно микросервисное и изначально я рассчитывал лишь на локальный его запуск, а соответственно всю связь между сервисами настроил прямо в docker compose файле, без использования nginx или чего-то подобного, rookie mistake, но для демонстрации деплоя вполне подойдет. Итак, сначала создайте Dockerfile своего приложения. В моем случае все получилось немного сложно, сначала я собираю докерфайлом мавена весь проект и копирую сгенерированные jar в папку проекта, т.к. я использовал мультимодульную структуру Maven проекта. Если у вас всего один сервис в проекте, то ваш докерфайл будет выглядеть достаточно просто:
FROM openjdk:17.0.2-jdk-slim
COPY target/shows-migrations-service-0.0.1-SNAPSHOT.jar .
CMD ["java", "-jar", "shows-migrations-service-0.0.1-SNAPSHOT.jar"]
Далее напишите compose файл, в который вы соберете все необходимые вам сервисы, а именно ваш сервис, базу данных, еще что-то по необходимости. В моем случае это было 3 сервиса, postgres и keycloak:
version: "3.8"
services:
postgres:
image: 'postgres:14-alpine'
container_name: postgres
restart: always
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
volumes:
- ./imports/init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- auth
keycloak:
image: quay.io/keycloak/keycloak:20.0.0
container_name: keycloak
restart: always
volumes:
- ./imports:/opt/keycloak/data/import
command: ['start-dev --import-realm --http-relative-path=/auth']
environment:
KC_DB: postgres
KC_DB_URL_HOST: postgres
KC_DB_URL_PORT: 5432
KC_DB_URL_DATABASE: postgres
KC_DB_USERNAME: postgres
KC_DB_PASSWORD: postgres
KEYCLOAK_ADMIN: admin
KC_DB_SCHEMA: public
KEYCLOAK_ADMIN_PASSWORD: admin
KEYCLOAK_FRONTEND_URL: http://localhost:8484/auth
ports:
- "8484:8080"
depends_on:
- postgres
links:
- "postgres:postgres"
networks:
- auth
...
shows-data:
image: shows-data-service
container_name: shows-data
restart: always
depends_on:
- postgres
- keycloak
- migrations
network_mode: host
environment:
POSTGRES_JDBC_URL: jdbc:postgresql://localhost:5432/postgres
KEYCLOAK_URL: http://localhost:8484/auth
SERVER_PORT: 8080
extra_hosts:
- "host.docker.internal:host-gateway"
...
networks:
auth:
driver: bridge
Как вы видите, достаточно настроек, и это я еще опустил 2 сервиса. Если коротко, я импорчу данные в postgres, импорчу realm в keycloak и настраиваю сервисы. Сервисы работают в сети "host", что значит, что они работают в сети инстанса, на самом деле это не обязательно, ведь в докер compose файле порты можно прокинуть, и при открытии портов в настройках нашего инстанса все заработает, но для чего-то мне это было нужно, уже не помню для чего, в общем, зависит от нужд вашего приложения. Далее остается настройка самого файла CircleCi. Т.к. он получается достаточно длинный, повторящиеся вещи уберу и приведу частями, с объяснением:
version: 2.1
jobs:
deploy-to-development:
docker:
- image: docker:20.10.9
steps:
- checkout
- setup_remote_docker
- run:
name: Build Docker Image
command: |
chmod +x ./build.sh
./build.sh
docker build -f Dockerfile-migrations -t migrations-service:latest .
- run:
name: Compress Docker Image
command: |
docker save migrations-service:latest | gzip > migrations-service.tar.gz
- run: ls -lh
- persist_to_workspace:
root: .
paths:
- migrations-service.tar.gz
- ./docker/
Здесь мы используем образ Докера, чтобы использовать его команды. Я запускаю свой sh файл для сборки приложения (тот, что собирает и копирует jarники, у вас скорее всего такого не будет), далее собирается докер образ вашего приложения, обязательно задайте ему тэг. Далее мы сохраняем этот образ и сжимаем его. И сохраняем получившийся файл и нужную папочку с файлами docker compose (в моем случае это папка, у вас может быть просто 1 файл).
transfer-and-run:
machine:
image: ubuntu-2004:202010-01
steps:
- attach_workspace:
at: .
- run:
name: Install SSH And Configure
command: |
echo $SSH_PRIVATE_KEY | base64 --decode > ./id_rsa
chmod 400 id_rsa
- run:
name: Stop Remote Docker-Compose
command: |
ssh -o "StrictHostKeyChecking=no" -i ./id_rsa $USER@$HOST '
if [ -f compose.yml ]; then
sudo docker-compose -f docker/compose.yml down --rmi all
sudo rm compose.yml
else
echo "compose.yml not found"
fi
'
- run:
name: Transfer Files
command: |
scp -o "StrictHostKeyChecking=no" -i ./id_rsa ./shows-frontend-service.tar.gz $USER@$HOST:~/
scp -o "StrictHostKeyChecking=no" -i ./id_rsa -r ./docker $USER@$HOST:~/
- run:
name: Decompress Docker Image | Run Compose
command: |
ssh -o "StrictHostKeyChecking=no" -i ./id_rsa $USER@$HOST '
gunzip -c ./shows-frontend-service.tar.gz | sudo docker load
rm ./*.tar.gz
cd docker
sudo docker compose -f compose.yml up -d
'
workflows:
deploy-to-dev:
jobs:
- deploy-to-development:
filters:
branches:
only:
- deploy
- transfer-and-run:
requires:
- deploy-to-development
filters:
branches:
only:
- deploy
И так, здесь как, мы видим, мы определяем вторую часть нашего деплоя, а именно трансфер файлов и их запуск. Делаем мы это используя уже образ Ubuntu, а не Докера. Здесь мы используем файлы с предыдущего шага, которые сохранили (workspace). Далее мы берем SSH_KEY, который мы заранее сохранили в ENV переменных проекта в Circleci в base64 виде, и сохраняем его в файлик, даем ему нужный доступ. Сами переменные Circleci хранит в зашифрованном виде и вроде как это безопасно. Альтернатива: делать то же самое, но на машине хоста и давать какой-то ключ на доступ к гиту, клонить проект гита и уже все делать на машине хоста, но как будто бы это не особо лучше. Далее мы используем этот ключ, чтобы подключиться по ssh к хосту, также используя переменные $USER и $HOST. Останавливаем докер файлик, удаляем лишние образы. Копируем нужные нам файлы на машину хоста (напоминаю, что некоторые я опустил, для краткости, так что не удивляйтесь, что названия скачут), и загружаем сжатые нами образы в докер, затем удаляем сжатые файлы. После чего запускаем compose файлик, и все сервисы должны запуститься. Также ниже вы видите настройки того, с какой ветки запускать нажи джобы, в моем случае это deploy.
После этого вы увидите в панели CircleCi, что все ваши шаги прошли и отмечены галочкой, после чего можете подключиться к машине хоста и проверить вручную, что все работает (правда не в моем случае, т.к. я накосячил немного со структурой самого приложения, но задеплоиться и запуститься все запустилось, так что это уже другой разговор). И, пока не забыл, покажу как добавить ENV переменные в проект: заходите в Settings Project и добавляете в Environment Variables (кстати только сейчас заметил, что оказывается там можно напрямую и SSH ключи добавить, наверное лучше так и делать в дальнейшем, но раз уже написал гайд, оставлю так):
И как открыть порты в google console: заходите на страницу вашего проекта (важно, не инстанса, а именно проекта), заходите в левом меню в "VPC Network -> Firewall", нажимаете сверху "Create firewall rule", даете название по желанию, обязательно ставите какой-нибудь тег, и разрешаете нужные вам порты (например, 8081). После чего заходите уже в ваш инстанс, нажимаете "Edit" и в "Network tags" добавляете тот тег, который задали на правило, и порт у вас откроется.
Полный код проекта и сам проект доступны на моем гите, если кто-то что-то не понял и ему нужен source (сам прекрасно понимаю это чувство, когда в гайде что-то не понятно, но при этом нет ссылки на исходники, надеюсь я в статье и гите никаких лишних данных не спалил). В любом случае, думаю этот гайд будет кому-то полезен, в конце концов это полезный опыт для разработчиков, попробовать подеплоить свои пет проекты самостоятельно, тем более что, если вам удастся зарегистрироваться на Амазоне удачно, то у вас будет целый год бесплатного хостинга, что вполне неплохо, чтобы задеплоить какой-то свой пет проект и указать ссылку на него в гите/резюме, за год то уж найдете работу (хотя, in this economy не факт, конечно).
А ну и чуть не забыл сказать, у CircleCi также есть ограничение по времени билда, используемого за месяц, поэтому рекомендую особо не злоупотреблять и деплоить только с какой-то стабильной ветки. Ну и, конечно, сейчас модно везде использовать Кубер, и голым докером почти никто не деплоит, но для простого приложения вполне сойдет, да и в случае падения приложения, свойство "restart: always" его запустит заново, так что какая-то стабильность все-таки присутствует. В любом случае, если вам понравилась статья, ссылки на меня найдете в профиле, всем спасибо за внимание.
Комментарии (19)
ajijiadduh
07.10.2023 15:38-1как можно стать ДевОпсом, не имея опыта программирования
легко
arzybek Автор
07.10.2023 15:38Ну то, что можно стать девопсом, не имея опыта программирования, я не сомневаюсь, другой вопрос насколько квалифицированным и хорошим девопсом можно стать, именно это и имелось ввиду
SGordon123
07.10.2023 15:38-2А нынче суета с иностранными кредитками не сложнее убунты на компе под столом? После того как окорокл снес россиян , я не пробовал, вот и интересуюсь ...
arzybek Автор
07.10.2023 15:38Не знаю, у меня не российские карты, российские нигде не принимают сейчас, это знаю разве что
Areso
07.10.2023 15:38У Оракла, точнее у его эквайринг партнёра, очень специфичное отношение к картам. Мою карту одной европейской страны не приняло даже без санкций.
После этого решил использовать более предсказуемые альтернативы (да, без халявы, но что поделать).
AzamatKomaev
07.10.2023 15:38+1Если нет возможности использовать зарубежные облачные сервисы из-за проблем с привязкой российских карт, то можно использовать Yandex Cloud с сервисом Serverless Containers. Есть определенный лимит по потреблению (Free tier), чтобы не платить за контейнер, а также весьма дешёвый Container Registry, который в первое время можно платить из гранта (там будет набегать небольшая сумма если хранить небольшие образы). А также скорее всего есть возможность автоматизировать процесс деплоя
arzybek Автор
07.10.2023 15:38Ну у меня, как видите, нет проблем с использованием зарубежных сервисов, была проблема конкретно с Амазоном, то ли из-за моей ошибки, то ли из-за банка, то ли из-за Амазона, в итоге просто перешел на Гугл, для тестирования пока хватит
Naves
07.10.2023 15:38+51) https://hub.docker.com/_/openjdk
This image is officially deprecated and all users are recommended to
find and use suitable replacements ASAP.
Image alternatives2) слишком много команд sudo
3) совершенно непонятно, что делать, если после деплоя новая версия не работает, как откатываться. Тут классический пинок про использование образов с тегом latest. По хорошему, должно быть видно какая версия ПО запущена на хосте.
Есть еще несколько вещей, которые режут глаз, например, как
по быстрому нагадитькопирование файлов в каталог пользователя без создания подкаталога-имени проекта, но тут уже вкусовщина.Сначала останавливаете приложение, потом копируете, и пытаетесь запуститься. И тут мы получаем заведомый простой, а если копирование произойдет с ошибкой, то опять простой, пока кто-то снова не нажмет кнопку.
Название задания
deploy-to-development
вводит в заблуждениеarzybek Автор
07.10.2023 15:38-1Про образ jdк: конечно, не принципиально, я как-то не обратил внимания, что он устаревший. Про судо, да вроде не много, только те, что на хосте, т.к. серверы обычно представляют такой доступ без пароля, а запускать докер без судо - нужны преднастройки, да и кто-то под предыдущими моими постами говорил, что так лучше не делать (или вы про rm и gunzip, там, наверное, можно и удалить, согласен). Насчёт тегов, согласен, не заморачивался, конечно, лучше версиями, и лучше сначала запускать, а затем удалять, насчёт этого вы правильно подметили, но в контексте статьи, думаю пойдет и так.
mc2
07.10.2023 15:38+2Добавить в группу docker, или начиная с docker 19.x добавлена возможность rootless, когда запуск контейнера не требует прав root. Меньше судо - безопаснее)
arzybek Автор
07.10.2023 15:38Ну да, то что можно в группу добавить - я так и делал, но в комментариях мне пытались доказывать, что это наоборот небезопасно, так как же лучше в итоге, в любом случае, понадобятся пред настройки сервера, которые не автоматизируешь, это кажется сложнее, чем просто добавить sudo
arzybek Автор
Господи, ладно еще за "низкий технический уровень" минусы ставят, это субъективно, кому-то низкий, кому-то сложный, но оказывается на Хабре можно минусить за "личную неприязнь к автору или компании", т.к. я никакую компанию не представляю как автор, получается кто-то из-за "личной неприязни" поставил минус (даже интересно чем же я успел такую неприязнь заработать, вроде статьи все хороший отклик получали), и как после этого убеждать людей делиться знаниями на Хабре... ????????
ky0
Статья нормальная. Кого-то может, например, покоробить религиозная принадлежность в подписи. Уверены, что анонсирование этого факта важно на Хабре?
arzybek Автор
Честно говоря, вы первый, кто об этом написал, да и это моя стандартная подпись в соц. сетях, так что если это для кого-то повод минусовать, то даже и не знаю что сказать ???? Ну, в конце концов, думаю это не так важно, предыдущие мои статьи собирали куда больше закладок, чем плюсов, я так предполагаю это из-за того, что обучающиеся/новенькие люди зачастую имеют новые аккаунты/не имеют возможности плюсовать, но могут пометить в закладки, как что-то полезное на потом, думаю на данный момент для меня это более объективный/адекватный критерий, как и просмотры (ну это самый очевидный критерий, люди заходят, смотрят, но аккаунта на Хабре не имеют, таких думаю большой процент все еще)
Tempelfeld
Не переживайте. Это царство двойных стандартов показывает свою толерантность. Продолжайте писать, Ваши статьи полезны и нужны!
arzybek Автор
Спасибо за добрые слова
X-yro
Блин, я херею с людей, религия это не повод неприязни, это так тупо ставить минусы из-за этого
arzybek Автор
Согласен, но когда-то такое уже было с другой моей статьей, по итогу она все равно набрала больше плюсов и кучу просмотров и закладок, рано или поздно, хороший материал оценят, я так думаю
UPD: Кто-то мне еще и все комментарии минусует, бывают же люди, заняться нечем, даже смешно немног
N4N
Я тоже принадлежу к одной из конфессий. Но мне кажется, что это не повод сообщать об этом на всех площадках всему миру. Вы же не вешаете на себя плакат "Я мусульманин" и не ходите так по городу? Религия - это только ваше и мне кажется, это очень личное, об этом не говорят публично. Тот, кто кричит на всех углах о величии Аллаха, Иисуса или Будды, лично у меня вызывает настороженность. Так часто поступают всякие аферисты от религии и псевдорелигиозные проповедники.