ProHoster > Blog > podávání > Vytvoření řetězce CI / CD a automatizace práce s Dockerem
Vytvoření řetězce CI / CD a automatizace práce s Dockerem
Své první webové stránky jsem napsal koncem 90. let. Poté bylo velmi snadné je uvést do funkčního stavu. Na nějakém sdíleném hostingu byl server Apache, na tento server bylo možné přistupovat přes FTP tak, že do řádku prohlížeče napíšete něco jako ftp://ftp.example.com. Poté bylo nutné zadat jméno a heslo a nahrát soubory na server. Byly jiné časy, všechno bylo tehdy jednodušší než teď.
Věci se za poslední dvě desetiletí hodně změnily. Místa se stala složitější, musí se před uvedením do výroby sestavit. Z jednoho jediného serveru se stalo mnoho serverů běžících za nástroji pro vyrovnávání zátěže, používání systémů správy verzí se stalo samozřejmostí.
Pro svůj osobní projekt jsem měl speciální konfiguraci. A věděl jsem, že potřebuji možnost nasadit web do produkce a provést pouze jednu akci: napsat kód do pobočky master na GitHubu. Věděl jsem také, že nechci spravovat obrovský cluster Kubernetes nebo používat technologii Docker Swarm nebo udržovat serverový park s moduly, agenty a všemi druhy složitosti, abych provozoval svou malou webovou aplikaci. Abych dosáhl cíle co nejvíce usnadnit práci, potřeboval jsem se s CI / CD seznámit.
Pokud máte malý projekt (v našem případě projekt Node.js) a rádi byste se naučili, jak automatizovat nasazení tohoto projektu a zároveň se ujistit, že to, co je uloženo v úložišti, přesně odpovídá tomu, co běží v produkci, pak si myslím, že by vás mohl zajímat tento článek.
Předpoklady
Od čtenáře tohoto článku se očekává, že bude mít základní znalosti příkazového řádku a skriptování v Bash. Navíc bude potřebovat účty Travis CI и Docker hub.
Cíle
Nebudu tvrdit, že tento článek lze bezvýhradně nazvat „průvodcem školením“. Jedná se spíše o dokument, ve kterém mluvím o tom, co jsem se naučil, a popisuji proces, který mi vyhovuje pro testování a nasazení kódu do výroby, prováděné v jednom automatizovaném průchodu.
Zde je to, jak můj pracovní postup nakonec vypadal.
Pro kód vložený do jakékoli jiné větve úložiště než master, jsou provedeny následující akce:
Zahájení projektu na Travis CI.
Provádějí se všechny testy jednotky, integrace a end-to-end testy.
Pouze pro kód, který skončí v master, provádí se následující:
Vše výše uvedené plus...
Vytvoření bitové kopie Dockeru na základě aktuálního kódu, nastavení a prostředí.
Hostování obrázku na Docker Hub.
Připojení k produkčnímu serveru.
Nahrání obrázku z Docker Hub na server.
Zastavte aktuální kontejner a spusťte nový na základě nového obrázku.
Pokud nevíte vůbec nic o Dockeru, obrázcích a kontejnerech, nebojte se. Řeknu vám o tom všechno.
Co je CI/CD?
Zkratka CI / CD znamená „continuous integration/continuous deployment“ – „kontinuální integrace / kontinuální nasazení“.
▍Nepřetržitá integrace
Nepřetržitá integrace je proces, kterým se vývojáři zavazují k hlavnímu úložišti zdrojového kódu projektu (obvykle větev master). Zároveň je kvalita kódu zajištěna prostřednictvím automatizovaného testování.
▍Nepřetržité nasazení
Nepřetržité zavádění je časté automatizované zavádění kódu do výroby. Druhá část zkratky CI / CD je někdy odhalena jako „nepřetržité doručování“ („nepřetržité doručování“). To je v podstatě totéž jako „nepřetržité zavádění“, ale „průběžné doručování“ znamená nutnost ručního potvrzení změn před zahájením procesu zavádění projektu.
Začínáme
Aplikace, na které jsem toto vše zvládl, se nazývá Vzít na vědomí. Toto je webový projekt, na kterém pracuji pro psaní poznámek. Nejprve jsem se o to pokusil JAMStack-projekt nebo jen front-end aplikace bez serveru, aby bylo možné využít standardní možnosti hostingu a nasazení projektu, které nabízí netlify. Jak rostla složitost aplikace, potřeboval jsem vytvořit její back-end, což znamenalo, že budu muset vytvořit vlastní strategii pro automatizovanou integraci a automatizované nasazení projektu.
V mém případě je aplikací Express server běžící v prostředí Node.js, obsluhující jednostránkovou aplikaci React a podporující zabezpečené API na straně serveru. Tato architektura sleduje strategii, kterou lze nalézt v toto průvodce ověřením plného zásobníku.
Konzultoval jsem s příteli, který je odborníkem na automatizaci, a zeptal se ho, co musím udělat, aby to všechno fungovalo tak, jak chci. Dal mi představu o tom, jak by měl vypadat automatizovaný pracovní postup nastíněný v části Cíle tohoto článku. Stanovení takových cílů znamenalo, že jsem potřeboval zjistit, jak používat Docker.
přístavní dělník
Docker je nástroj, který díky technologii kontejnerizace usnadňuje distribuci aplikací a také jejich nasazení a provoz ve stejném prostředí, i když samotná platforma Docker běží v různých prostředích. Nejprve jsem potřeboval dostat do rukou nástroje příkazového řádku Docker (CLI). Instrukce Instalační příručka pro Docker není příliš přehledná, ale můžete se z ní dozvědět, že abyste mohli provést první krok instalace, musíte si stáhnout Docker Desktop (pro Mac nebo Windows).
Docker Hub je přibližně stejný jako GitHub pro git repozitáře nebo registry Npm pro balíčky JavaScript. Toto je online úložiště obrázků Docker. Zde se připojuje Docker Desktop.
Chcete-li tedy začít s Dockerem, musíte udělat dvě věci:
Poté můžete zkontrolovat, zda rozhraní Docker CLI funguje spuštěním následujícího příkazu a zkontrolovat verzi Dockeru:
docker -v
Poté se přihlaste do Docker Hub zadáním svého uživatelského jména a hesla, když budete požádáni:
docker login
Abyste mohli používat Docker, musíte rozumět konceptům obrázků a kontejnerů.
▍Obrázky
Obrázek je jakýsi plán obsahující pokyny pro stavbu kontejneru. Toto je neměnný snímek nastavení systému souborů a aplikací. Vývojáři mohou snadno sdílet obrázky.
# Вывод сведений обо всех образах
docker images
Tento příkaz vygeneruje tabulku s následujícím názvem:
REPOSITORY TAG IMAGE ID CREATED SIZE
---
Dále se podíváme na několik příkladů příkazů ve stejném formátu – nejprve je zde příkaz s komentářem a poté příklad toho, co může mít výstup.
▍Kontejnery
Kontejner je spustitelný balíček, který obsahuje vše potřebné ke spuštění aplikace. Aplikace s tímto přístupem bude vždy fungovat stejně, bez ohledu na infrastrukturu: v izolovaném prostředí a ve stejném prostředí. Hovoříme o tom, že instance stejného obrázku jsou spouštěny v různých prostředích.
# Перечисление всех контейнеров
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
---
▍Značky
Značka je označení konkrétní verze obrázku.
▍Rychlý přehled příkazů Dockeru
Zde je přehled některých běžně používaných příkazů Dockeru.
Vím, jak spustit produkční aplikaci lokálně. Mám webpack config pro vytvoření hotové aplikace React. Dále mám příkaz, který spustí server založený na Node.js na portu 5000. Vypadá to takto:
npm i # установка зависимостей
npm run build # сборка React-приложения
npm run start # запуск Node-сервера
Je třeba poznamenat, že pro tento materiál nemám vzorovou aplikaci. Ale zde pro experimenty postačí jakákoli jednoduchá aplikace Node.
Abyste mohli kontejner používat, budete muset zadat pokyny společnosti Docker. To se provádí pomocí souboru s názvem Dockerfileumístěný v kořenovém adresáři projektu. Tento soubor se na první pohled zdá poněkud nesrozumitelný.
Ale to, co obsahuje, pouze popisuje ve speciálních příkazech něco jako nastavení pracovního prostředí. Zde jsou některé z těchto příkazů:
Z — Tento příkaz spustí soubor. Určuje základní obrázek, ze kterého je kontejner sestaven.
COPY - Kopírování souborů z místního zdroje do kontejneru.
WORKDIR - Nastavení pracovního adresáře pro následující příkazy.
VSTUPNÍ BOD — Označení příkazu, který se má provést.
Dockerfile může vypadat nějak takto:
# Загрузить базовый образ
FROM node:12-alpine
# Скопировать файлы из текущей директории в директорию app/
COPY . app/
# Использовать app/ в роли рабочей директории
WORKDIR app/
# Установить зависимости (команда npm ci похожа npm i, но используется для автоматизированных сборок)
RUN npm ci --only-production
# Собрать клиентское React-приложение для продакшна
RUN npm run build
# Прослушивать указанный порт
EXPOSE 5000
# Запустить Node-сервер
ENTRYPOINT npm run start
V závislosti na zvoleném základním obrazu možná budete muset nainstalovat další závislosti. Faktem je, že některé základní obrazy (jako Node Alpine Linux) jsou navrženy tak, aby byly co nejkompaktnější. V důsledku toho nemusí obsahovat některé programy, které očekáváte.
▍Vytváření, označování a provozování kontejneru
Lokální montáž a spuštění kontejneru je po nás Dockerfileúkoly jsou celkem jednoduché. Před odesláním obrázku do Docker Hub je třeba jej lokálně otestovat.
▍Montáž
Nejprve musíte sbírat obraz, s uvedením názvu a případně značky (pokud není zadána žádná značka, systém automaticky přiřadí značku k obrázku latest).
# Сборка образа
docker build -t <image>:<tag> .
Po spuštění tohoto příkazu můžete sledovat, jak Docker vytváří obrázek.
Sending build context to Docker daemon 2.88MB
Step 1/9 : FROM node:12-alpine
---> ...выполнение этапов сборки...
Successfully built 123456789123
Successfully tagged <image>:<tag>
Budování může trvat několik minut - vše závisí na tom, kolik závislostí máte. Po dokončení sestavení můžete příkaz spustit docker images a podívejte se na popis vašeho nového obrázku.
REPOSITORY TAG IMAGE ID CREATED SIZE
<image> latest 123456789123 About a minute ago x.xxGB
▍Spusťte
Obrázek byl vytvořen. A to znamená, že na jeho základě můžete spustit kontejner. Protože chci mít přístup k aplikaci běžící v kontejneru na adrese localhost:5000, i, na levé straně páru 5000:5000 v následující sadě příkazů 5000. Na pravé straně je kontejnerový port.
# Запуск с использованием локального порта 5000 и порта контейнера 5000
docker run -p 5000:5000 <image>:<tag>
Nyní, když je kontejner vytvořen a spuštěn, můžete použít příkaz docker ps a podívejte se na informace o tomto kontejneru (nebo můžete použít příkaz docker ps -a, který zobrazuje informace o všech kontejnerech, nejen o běžících).
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
987654321234 <image> "/bin/sh -c 'npm run…" 6 seconds ago Up 6 seconds 0.0.0.0:5000->5000/tcp stoic_darwin
Pokud nyní půjdete do localhost:5000 - vidíte stránku běžící aplikace, která vypadá úplně stejně jako stránka aplikace běžící v produkčním prostředí.
▍Přiřazení a zveřejnění štítků
Abychom mohli použít jeden z vytvořených obrázků na produkčním serveru, musíme mít možnost stáhnout tento obrázek z Docker Hub. To znamená, že nejprve musíte vytvořit úložiště pro projekt na Docker Hub. Poté budeme mít místo, kam můžeme obrázek poslat. Obrázek je třeba přejmenovat tak, aby jeho název začínal naším uživatelským jménem Docker Hub. Poté by měl následovat název úložiště. Na konec jména lze umístit libovolný tag. Níže je uveden příklad pojmenování obrázků podle tohoto schématu.
Nyní můžete vytvořit obrázek s novým přiřazeným názvem a spustit příkaz docker push pro odeslání do úložiště Docker Hub.
docker build -t <username>/<repository>:<tag> .
docker tag <username>/<repository>:<tag> <username>/<repository>:latest
docker push <username>/<repository>:<tag>
# На практике это может выглядеть, например, так:
docker build -t user/app:v1.0.0 .
docker tag user/app:v1.0.0 user/app:latest
docker push user/app:v1.0.0
Pokud vše půjde dobře, bude obrázek k dispozici na Docker Hub a lze jej snadno nahrát na server nebo sdílet s ostatními vývojáři.
Další kroky
Nyní jsme ověřili, že aplikace ve formě kontejneru Docker běží lokálně. Nahráli jsme kontejner do Docker Hub. To vše znamená, že jsme již velmi dobře pokročili k našemu cíli. Nyní musíme vyřešit další dvě otázky:
Nastavení nástroje CI pro testování a nasazení kódu.
Nastavení produkčního serveru tak, aby si mohl stáhnout a spustit náš kód.
Nutno podotknout, že zde můžete využít jinou kombinaci služeb. Například místo Travis CI můžete použít CircleCI nebo Github Actions. A místo DigitalOcean - AWS nebo Linode.
Rozhodli jsme se spolupracovat s Travisem CI a v této službě už mám něco nastaveného. Proto nyní stručně pohovořím o tom, jak jej připravit na práci.
Travis CI
Travis CI je nástroj pro testování a nasazení kódu. Nechci zabíhat do detailů nastavení Travis CI, protože každý projekt je jedinečný a nepřinese mnoho užitku. Pokud se však rozhodnete používat Travis CI, proberu základy, abyste mohli začít. Ať už si vyberete cokoli – Travis CI, CircleCI, Jenkins nebo něco jiného, všude budou platit podobné konfigurační metody.
Chcete-li začít s Travis CI, přejděte na webové stránky projektu a vytvořte si účet. Poté integrujte Travis CI se svým účtem GitHub. Při nastavování systému budete muset určit úložiště, které chcete automatizovat, a povolit k němu přístup. (Používám GitHub, ale jsem si jistý, že Travis CI se dokáže integrovat s BitBucket, GitLab a dalšími podobnými službami).
Při každém spuštění Travis CI se spustí server, který provede příkazy uvedené v konfiguračním souboru, včetně nasazení příslušných větví úložiště.
▍Životní cyklus práce
Nazván konfigurační soubor Travis CI .travis.yml a uloženy v kořenovém adresáři projektu, podporuje koncept událostí životní cyklus úkoly. Zde jsou události seřazené v pořadí, v jakém k nim došlo:
apt addons
cache components
before_install
install
before_script
script
before_cache
after_success или after_failure
before_deploy
deploy
after_deploy
after_script
▍ Testování
V konfiguračním souboru nastavím místní Travis CI server. Jako jazyk jsem zvolil Node 12 a řekl systému, aby nainstaloval závislosti potřebné k používání Dockeru.
Vše uvedené v .travis.yml, budou provedeny u všech požadavků na stažení do všech větví úložiště, pokud není uvedeno jinak. Toto je užitečná funkce, protože to znamená, že můžeme otestovat veškerý kód, který jde do úložiště. To vám umožní zjistit, zda je kód připraven k zápisu do pobočky. mastera zda to naruší proces sestavení projektu. V této globální konfiguraci vše nainstaluji lokálně, spustím na pozadí dev server Webpack (toto je funkce mého pracovního postupu) a spustím testy.
Pokud chcete, aby vaše úložiště zobrazovalo ikony pokrytí kódem, zde můžete najít rychlý návod, jak používat Jest, Travis CI a kombinézu ke shromažďování a zobrazování těchto informací.
Zde je tedy obsah souboru .travis.yml:
# Установить язык
language: node_js
# Установить версию Node.js
node_js:
- '12'
services:
# Использовать командную строку Docker
- docker
install:
# Установить зависимости для тестов
- npm ci
before_script:
# Запустить сервер и клиент для тестов
- npm run dev &
script:
# Запустить тесты
- npm run test
Zde končí akce, které se provádějí pro všechny větve úložiště a pro žádosti o stažení.
▍ Nasazení
Na základě předpokladu, že všechny automatizované testy proběhly úspěšně, můžeme volitelně nasadit kód na produkční server. Protože to chceme udělat pouze pro kód pobočky master, dáváme systému příslušné pokyny v nastavení nasazení. Než se pokusíte použít kód, na který se ve vašem projektu podíváme příště, rád bych vás upozornil, že musíte mít skutečný skript, který je volán k nasazení.
deploy:
# Собрать Docker-контейнер и отправить его на Docker Hub
provider: script
script: bash deploy.sh
on:
branch: master
Skript nasazení dělá dvě věci:
Vytvoření, označení a odeslání obrázku do Docker Hub pomocí nástroje CI (v našem případě je to Travis CI).
Načtení obrázku na server, zastavení starého kontejneru a spuštění nového (v našem případě server běží na platformě DigitalOcean).
Nejprve musíte nastavit automatický proces vytváření, označování a odesílání obrázku do Docker Hub. To vše je velmi podobné tomu, co jsme již dělali ručně, až na to, že zde potřebujeme strategii pro přidělování jedinečných značek obrázkům a automatizaci přihlašování. Měl jsem potíže s některými detaily implementačního skriptu, jako je strategie označování, přihlašování, kódování klíčů SSH, navazování připojení SSH. Ale naštěstí můj přítel umí bash, stejně jako mnoho dalších věcí, velmi dobře. Pomohl mi napsat tento scénář.
První částí skriptu je tedy odeslání obrázku do Docker Hub. To je docela jednoduché. Schéma značkování, které jsem použil, zahrnuje kombinaci hash git a značky git, pokud existuje. To zajišťuje, že štítek je jedinečný a usnadňuje identifikaci sestavy, na které je založen. DOCKER_USERNAME и DOCKER_PASSWORD jsou uživatelem definované proměnné prostředí, které lze nastavit pomocí rozhraní Travis CI. Travis CI bude automaticky zpracovávat citlivá data, aby se nedostala do nepovolaných rukou.
Zde je první část scénáře deploy.sh.
#!/bin/sh
set -e # Остановить скрипт при наличии ошибок
IMAGE="<username>/<repository>" # Образ Docker
GIT_VERSION=$(git describe --always --abbrev --tags --long) # Git-хэш и теги
# Сборка и тегирование образа
docker build -t ${IMAGE}:${GIT_VERSION} .
docker tag ${IMAGE}:${GIT_VERSION} ${IMAGE}:latest
# Вход в Docker Hub и выгрузка образа
echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
docker push ${IMAGE}:${GIT_VERSION}
Jaká bude druhá část skriptu závisí zcela na tom, kterého hostitele používáte a jak je organizováno připojení k němu. V mém případě, protože používám Digital Ocean, se příkazy používají k připojení k serveru doctl. Při práci s Aws bude použit nástroj aws, a tak dále.
Nastavení serveru nebylo nijak zvlášť obtížné. Nastavil jsem tedy droplet na základě základního obrázku. Nutno podotknout, že mnou zvolený systém vyžaduje jednorázovou ruční instalaci Dockeru a jednorázové ruční spuštění Dockeru. K instalaci Dockeru jsem použil Ubuntu 18.04, takže pokud také používáte Ubuntu, můžete jednoduše sledovat tento jednoduché vedení.
Nemluvím zde o konkrétních příkazech pro službu, protože tento aspekt se může v různých případech značně lišit. Uvedu pouze obecný plán akcí, které mají být provedeny po připojení přes SSH k serveru, kde bude projekt nasazen:
Musíte najít kontejner, který právě běží, a zastavit jej.
Poté musíte na pozadí spustit nový kontejner.
Budete muset nastavit místní port serveru na 80 - to vám umožní vstoupit na stránku na adrese formuláře example.com, bez určení portu, spíše než pomocí adresy jako example.com:5000.
A nakonec musíte odstranit všechny staré kontejnery a obrázky.
Zde je pokračování scénáře.
# Найти ID работающего контейнера
CONTAINER_ID=$(docker ps | grep takenote | cut -d" " -f1)
# Остановить старый контейнер, запустить новый, очистить систему
docker stop ${CONTAINER_ID}
docker run --restart unless-stopped -d -p 80:5000 ${IMAGE}:${GIT_VERSION}
docker system prune -a -f
Některé věci, na které si dát pozor
Je možné, že když se připojíte k serveru přes SSH z Travis CI, uvidíte varování, které vám nedovolí pokračovat v instalaci, protože systém bude čekat na odpověď uživatele.
The authenticity of host '<hostname> (<IP address>)' can't be established.
RSA key fingerprint is <key fingerprint>.
Are you sure you want to continue connecting (yes/no)?
Dozvěděl jsem se, že řetězcový klíč lze zakódovat v base64, aby byl uložen ve formě, ve které se s ním dá pohodlně a spolehlivě pracovat. Ve fázi instalace můžete dekódovat veřejný klíč a zapsat jej do souboru known_hosts abyste se zbavili výše uvedené chyby.
Stejný přístup lze použít se soukromým klíčem při navazování spojení, protože pro přístup k serveru můžete potřebovat soukromý klíč. Při práci s klíčem stačí zajistit, aby byl bezpečně uložen v proměnné prostředí Travis CI a nikde nebyl zobrazen.
Další věc, kterou je třeba poznamenat, je, že možná budete muset spustit celý skript nasazení jako jeden řádek, například pomocí doctl. To může vyžadovat určité úsilí navíc.
doctl compute ssh <droplet> --ssh-command "все команды будут здесь && здесь"
TLS/SSL a vyvažování zátěže
Poté, co jsem provedl vše výše uvedené, poslední problém, který jsem měl, byl, že server neměl SSL. Vzhledem k tomu, že používám server Node.js, za účelem vynucení do práce reverzní proxy Nginx a Let's Encrypt, musíte hodně makat.
Opravdu se mi nechtělo dělat všechna tato nastavení SSL ručně, tak jsem si jen vytvořil load balancer a zaznamenal o něm informace do DNS. V případě DigitalOcean je například vytvoření automaticky obnovujícího certifikátu s vlastním podpisem na nástroji pro vyrovnávání zatížení jednoduchým, bezplatným a rychlým postupem. Tento přístup má další výhodu v tom, že je v případě potřeby velmi snadné nastavit SSL na více serverech běžících za nástrojem pro vyrovnávání zatížení. To umožňuje samotným serverům vůbec „nemyslet“ na SSL, ale zároveň jako obvykle používat port 80. Konfigurace SSL na nástroji pro vyrovnávání zatížení je tedy mnohem jednodušší a pohodlnější než alternativní metody konfigurace SSL.
Nyní můžete zavřít všechny porty na serveru, které přijímají příchozí připojení - kromě portu 80, který se používá ke komunikaci s vyrovnávačem zátěže a portem 22 pro SSH. V důsledku toho selže pokus o přímé spojení se serverem na jiných portech než na těchto dvou.
Výsledky
Poté, co jsem udělal vše, o čem jsem mluvil v tomto článku, mě už platforma Docker ani koncept automatizovaných řetězců CI / CD neděsily. Podařilo se mi nastavit kontinuální integrační řetězec, během kterého je kód testován před tím, než jde do výroby, a kód je automaticky nasazen na server. To vše je pro mě stále relativně nové a jsem si jistý, že existují způsoby, jak můj automatizovaný pracovní postup zlepšit a zefektivnit. Takže pokud máte nějaké nápady na toto - dejte mě vědět. Doufám, že vám tento článek pomohl ve vašem úsilí. Chci věřit, že čtením jste se naučili tolik, co jsem se naučil já, zatímco jsem se zabýval vším, o čem jsem v něm vyprávěl.
PS V našem tržiště je tam obrázek přístavní dělník, který se nainstaluje jedním kliknutím. Můžete zkontrolovat, jak kontejnery fungují VPS. Všichni noví zákazníci mají 3 dny na testování zdarma.
Vážení čtenáři! Používáte ve svých projektech CI/CD technologie?