在本文中,我將分享我使用 Plesk 控制面板和 Github Actions 設置 CI/CD 的經驗。 今天我們將學習如何部署一個名為“Helloworld”的簡單項目。 它是用 Flask Python 框架編寫的,帶有 Celery worker 和 Angular 8 前端。
在本文的第一部分,我們將查看我們的項目及其部分。 在第二部分,我們將了解如何設置 Plesk 並安裝必要的擴展和組件(DB、RabbitMQ、Redis、Docker 等)。
在第三部分中,我們將最終弄清楚如何設置管道以將我們的項目部署到開發和生產環境中的服務器。 然後我們將在服務器上啟動該站點。
是的,我忘了自我介紹。 我叫 Oleg Borzov,是 Domclick 抵押貸款經理 CRM 團隊的一名全棧開發人員。
項目概覽
首先,讓我們看一下兩個項目存儲庫 - 後端和前端 - 並檢查代碼。
後端:燒瓶+芹菜
對於後面的部分,我採用了一組在 Python 開發人員中非常流行的:Flask 框架(用於 API)和 Celery(用於任務隊列)。 SQLAchemy 用作 ORM。 Alembic 用於遷移。 對於句柄中的 JSON 驗證 - Marshmallow。
В
/ping
- 檢查可用性;- 處理註冊、授權、取消授權和獲得授權用戶;
- 將任務放入 Celery 隊列的電子郵件句柄。
send_mail_task
.
在文件夾中
docker
有兩個 Dockerfiles (base.dockerfile
建立一個很少改變的基礎形象和Dockerfile
用於主要組件);.env_files
- 帶有針對不同環境的環境變量的文件。
項目根目錄下有四個 docker-compose 文件:
docker-compose.local.db.yml
為發展建立一個本地數據庫;docker-compose.local.workers.yml
用於 worker、數據庫、Redis 和 RabbitMQ 的本地提升;docker-compose.test.yml
在部署期間運行測試;docker-compose.yml
用於部署。
我們感興趣的最後一個文件夾 -
deploy.sh
— 啟動遷移和部署。 在 Github Actions 中構建和運行測試後在服務器上運行;rollback.sh
- 將容器回滾到先前版本的程序集;curl_tg.sh
- 向 Telegram 發送部署通知。
Angular 前端
- 帶有用於發送電子郵件的表單和退出按鈕的主頁。
- 登錄頁面。
- 註冊頁面。
主頁看起來苦行僧:
根目錄下有兩個文件 Dockerfile
и docker-compose.yml
,以及熟悉的文件夾 .ci-cd
腳本比後台存儲庫中的腳本略少(刪除了用於運行測試的腳本)。
在 Plesk 中啟動項目
讓我們從設置 Plesk 並為我們的站點創建訂閱開始。
安裝擴展
在 Plesk 中,我們需要四個擴展:
Docker
在 Plesk 管理面板中管理和可視化顯示容器的狀態;Git
在服務器上配置部署步驟;Let's Encrypt
生成(並自動更新)免費的 TLS 證書;Firewall
配置傳入流量的過濾。
您可以通過擴展部分中的 Plesk 管理面板安裝它們:
我們不會考慮擴展的詳細設置,默認設置將用於我們的演示目的。
創建訂閱和站點
接下來,我們需要為我們的 helloworld.ru 網站創建一個訂閱,並在那裡添加 dev.helloworld.ru 子域。
- 為 helloworld.ru 域創建訂閱並為系統用戶指定登錄密碼:
選中頁面底部的複選框 使用 Let's Encrypt 保護域如果我們想為站點設置 HTTPS: - 接下來,在此訂閱中,創建一個子域 dev.helloworld.ru(您還可以為其頒發免費的 TLS 證書):
安裝服務器組件
我們有一台服務器 操作系統 Debian Stretch 9.12 並安裝了控制面板 Plesk 黑曜石 18.0.27.
我們需要為我們的項目安裝和配置:
- PostgreSQL(在我們的例子中,將有一台服務器有兩個數據庫用於開發和生產環境)。
- RabbitMQ(相同的實例,具有不同的虛擬主機環境)。
- 兩個 Redis 實例(用於開發和生產環境)。
- Docker 註冊表(用於本地存儲構建的 Docker 映像)。
- Docker 註冊表的 UI。
PostgreSQL的
Plesk 已經帶有 PostgreSQL DBMS,但不是最新版本(在撰寫 Plesk Obsidian 時
網上有很多關於在 Debian 上安裝 Postgres 的詳細說明(
wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O - | sudo apt-key add -
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main" >> /etc/apt/sources.list.d/pgdg.list'
sudo apt-get update
sudo apt-get install postgresql postgresql-contrib
考慮到 PostgreSQL 的默認設置相當一般,有必要更正配置。 這將幫助我們 /etc/postgresql/12/main/postgresql.conf
給那些提供的。 此處應注意,此類計算器並非靈丹妙藥,應根據您的硬件、應用程序和查詢複雜性對基數進行更精確的調整。 但這足以開始。
除了計算器建議的設置外,我們還更改了 postgresql.conf
默認端口 5432 到另一個端口(在我們的示例中 - 53983).
更改配置文件後,使用以下命令重新啟動 postgresql-server:
service postgresql restart
我們已經安裝並配置了 PostgreSQL。 現在讓我們創建一個數據庫,開發環境和生產環境的用戶,並賦予用戶管理數據庫的權限:
$ su - postgres
postgres:~$ create database hw_dev_db_name;
CREATE DATABASE
postgres:~$ create user hw_dev_db_user with password 'hw_dev_db_password';
CREATE ROLE
postgres:~$ grant ALL privileges ON database hw_dev_db_name to hw_dev_db_user;
GRANT
postgres:~$ create database hw_prod_db_name;
CREATE DATABASE
postgres:~$ create user hw_prod_db_user with password 'hw_prod_db_password';
CREATE ROLE
postgres:~$ grant ALL privileges ON database hw_prod_db_name to hw_prod_db_user;
GRANT
的RabbitMQ
讓我們繼續安裝 Celery 的消息代理 RabbitMQ。 在 Debian 上安裝它非常簡單:
wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb
sudo dpkg -i erlang-solutions_1.0_all.deb
sudo apt-get update
sudo apt-get install erlang erlang-nox
sudo add-apt-repository 'deb http://www.rabbitmq.com/debian/ testing main'
wget -O- https://www.rabbitmq.com/rabbitmq-release-signing-key.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install rabbitmq-server
安裝後,我們需要創建 虛擬主機,用戶並授予必要的權利:
sudo rabbitmqctl add_user hw_dev_amqp_user hw_dev_amqp_password
sudo rabbitmqctl set_user_tags hw_dev_amqp_user administrator
sudo rabbitmqctl add_vhost hw_dev_vhost
sudo rabbitmqctl set_permissions -p hw_dev_vhost hw_dev_amqp_user ".*" ".*" ".*"
sudo rabbitmqctl add_user hw_prod_amqp_user hw_prod_amqp_password
sudo rabbitmqctl set_user_tags hw_prod_amqp_user administrator
sudo rabbitmqctl add_vhost hw_prod_vhost
sudo rabbitmqctl set_permissions -p hw_prod_vhost hw_prod_amqp_user ".*" ".*" ".*"
Redis的
現在讓我們為我們的應用程序安裝和配置最後一個組件 - Redis。 它將用作存儲 Celery 任務結果的後端。
我們將使用擴展為開發和生產環境提供兩個帶有 Redis 的 Docker 容器 Docker
對於 Plesk。
- 我們轉到 Plesk,轉到擴展部分,查找 Docker 擴展並安裝它(我們需要免費版本):
- 轉到已安裝的擴展程序,通過搜索找到圖像
redis bitnami
並安裝最新版本: - 我們進入下載的容器並調整配置:指定端口、分配的最大 RAM 大小、環境變量中的密碼以及掛載卷:
- 我們為 prod 容器執行步驟 2-3,在設置中我們只更改參數:端口、密碼、RAM 大小和服務器上卷文件夾的路徑:
Docker 註冊表
除了基礎服務,如果服務器上放上自己的Docker鏡像倉庫就好了。 幸運的是,服務器空間現在相當便宜(肯定比 DockerHub 訂閱便宜),而且設置私有存儲庫的過程非常簡單。
我們想要:
- 可在子域上訪問的受密碼保護的 Docker 存儲庫
https://docker.helloworld.ru ; - 用於查看存儲庫中圖像的 UI,位於
https://docker-ui.helloworld.ru .
要做到這一點:
- 讓我們在訂閱的 Plesk 中創建兩個子域:docker.helloworld.ru 和 docker-ui.helloworld.ru,並為它們配置 Let's Encrypt 證書。
- 將文件添加到 docker.helloworld.ru 子域文件夾
docker-compose.yml
內容如下:version: "3" services: docker-registry: image: "registry:2" restart: always ports: - "53985:5000" environment: REGISTRY_AUTH: htpasswd REGISTRY_AUTH_HTPASSWD_REALM: basic-realm REGISTRY_AUTH_HTPASSWD_PATH: /auth/.htpasswd REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data volumes: - ./.docker-registry.htpasswd:/auth/.htpasswd - ./data:/data docker-registry-ui: image: konradkleine/docker-registry-frontend:v2 restart: always ports: - "53986:80" environment: VIRTUAL_HOST: '*, https://*' ENV_DOCKER_REGISTRY_HOST: 'docker-registry' ENV_DOCKER_REGISTRY_PORT: 5000 links: - 'docker-registry'
- 在 SSH 下,我們將在 Docker 存儲庫中生成用於 Basic 授權的 .htpasswd 文件:
htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password
- 收集和提升容器:
docker-compose up -d
- 我們需要將 Nginx 重定向到我們的容器。 這可以通過 Plesk 完成。
需要為 docker.helloworld.ru 和 docker-ui.helloworld.ru 子域完成以下步驟:
在第 開發工具 我們的網站去 Docker 代理規則:
並添加一條規則來將傳入流量代理到我們的容器:
- 我們檢查我們是否可以從本地機器登錄到我們的容器:
$ docker login docker.helloworld.ru -u hw_docker_admin -p hw_docker_password WARNING! Using --password via the CLI is insecure. Use --password-stdin. Login Succeeded
- 我們還檢查一下 docker-ui.helloworld.ru 子域的運行情況:
當您單擊瀏覽存儲庫時,瀏覽器將顯示一個授權窗口,您需要在其中輸入存儲庫的用戶名和密碼。 之後,我們將被重定向到一個包含存儲庫列表的頁面(現在,它對您來說是空的):
在 Plesk 防火牆中打開端口
安裝和配置組件後,我們需要打開端口,以便從 Docker 容器和外部網絡訪問組件。
讓我們看看如何使用我們之前安裝的 Plesk 防火牆擴展來做到這一點。
- 去 工具與設置 > 設置 > 防火牆:
- 去 修改 Plesk 防火牆規則 > 添加自定義規則 並為 Docker 子網打開以下 TCP 端口 (172.0.0.0 / 8):
RabbitMQ:1883、4369、5671-5672、25672、61613-61614
雷迪斯:32785、32786 - 我們還將添加一條規則,向外界開放 PostgreSQL 端口和 RabbitMQ 管理面板:
- 使用 Apply Changes 按鈕應用規則:
在 Github Actions 中設置 CI/CD
讓我們開始討論最有趣的部分——設置持續集成管道並將我們的項目交付到服務器。
該管道將由兩部分組成:
- 構建圖像並運行測試(用於後端)——在 Github 端;
- 在服務器上運行遷移(用於後端)和部署容器。
部署到 Plesk
讓我們先處理第二點(因為第一點取決於它)。
我們將使用 Plesk 的 Git 擴展配置部署過程。
考慮一個後端存儲庫的 Prod 環境示例。
- 我們轉到我們的 Helloworld 網站的訂閱並轉到 Git 子部分:
- 將指向我們的 Github 存儲庫的鏈接插入“遠程 Git 存儲庫”字段並更改默認文件夾
httpdocs
給另一個(例如。/httpdocs/hw_back
): - 複製上一步中的 SSH 公鑰,然後
添加 它在 Github 設置中。 - 在第 2 步的屏幕上單擊確定,之後我們將被重定向到 Plesk 中的存儲庫頁面。 現在我們需要將存儲庫配置為在提交到 master 分支時更新。 為此,請訪問 存儲庫設置 並保存值
Webhook URL
(我們稍後在設置 Github Actions 時需要它): - 在上一段屏幕上的 Actions 字段中,輸入啟動部署的腳本:
cd {REPOSITORY_ABSOLUTE_PATH} .ci-cd/deploy.sh {ENV} {DOCKER_REGISTRY_HOST} {DOCKER_USER} {DOCKER_PASSWORD} {TG_BOT_TOKEN} {TG_CHAT_ID}
其中:
{REPOSITORY_ABSOLUTE_PATH}
- 服務器上後端存儲庫的 prod 文件夾的路徑;
{ENV}
- 環境(開發/生產),在我們的例子中prod
;
{DOCKER_REGISTRY_HOST}
- 我們的 docker 存儲庫的主機
{TG_BOT_TOKEN}
— Telegram 機器人令牌;
{TG_CHAT_ID}
— 用於發送通知的聊天/頻道的 ID。腳本示例:
cd /var/www/vhosts/helloworld.ru/httpdocs/hw_back/ .ci-cd/deploy.sh dev docker.helloworld.ru docker_user docker_password 12345678:AAbcdEfghCH1vGbCasdfSAs0K5PALDsaw -1001234567890
- 從我們的訂閱中添加一個用戶到 Docker 組(這樣他們就可以管理容器):
sudo usermod -aG docker helloworld_admin
後端存儲庫和前端的開發環境以相同的方式設置。
Github Actions 中的部署管道
讓我們繼續在 Github Actions 中設置 CI/CD 管道的第一部分。
後端
管道描述於
不過在解析之前,我們先在Github中填寫我們需要的Secret變量。 為此,請訪問 設置 -> 秘密:
DOCKER_REGISTRY
- 我們的 Docker 存儲庫的主機 (docker.helloworld.ru);DOCKER_LOGIN
- 登錄到 Docker 存儲庫;DOCKER_PASSWORD
- 密碼;DEPLOY_HOST
— Plesk 管理面板可用的主機(例如:helloworld.com :8443 或123.4.56.78 :8443);DEPLOY_BACK_PROD_TOKEN
- 用於部署到服務器上的 prod-repository 的令牌(我們在第 4 頁的 Plesk 部署中獲得);DEPLOY_BACK_DEV_TOKEN
- 用於部署到服務器上的開發存儲庫的令牌。
部署過程很簡單,包括三個主要步驟:
- 在我們的存儲庫中構建和發布圖像;
- 基於新構建的鏡像在容器中運行測試;
- 根據分支(dev/master)部署到所需的環境。
前端
站點設置
通過 Nginx 代理流量
好吧,我們已經走到了盡頭。 它仍然只是配置通過 Nginx 將傳入和傳出流量代理到我們的容器。 我們已經在 Docker Registry 設置的第 5 步中介紹了這個過程。 在開發環境和生產環境中,應該對後面和前面的部分重複相同的操作。
我將提供設置的屏幕截圖。
後端
前端
重要說明. 所有 URL 都將被代理到前端容器,除了那些以 /api/
- 他們將被代理到後面的容器(所以 在後面的容器中,所有處理程序都必須以 /api/
).
結果
現在我們的站點應該可以在 helloworld.ru 和 dev.helloworld.ru(分別是產品環境和開發環境)上訪問。
總的來說,我們學習瞭如何在 Flask 和 Angular 中準備一個簡單的應用程序,並在 Github Actions 中設置一個管道以將其部署到運行 Plesk 的服務器上。
我將使用代碼複製存儲庫的鏈接:
來源: www.habr.com