برنامه نویسی

استقرار AWS ECS Fargate خود را با Terraform و GitLab CI/CD با استفاده از برنامه پایتون ساده کنید.

نموداری که یک خط لوله CI/CD و زیرساخت AWS برای استقرار یک برنامه کاربردی را نشان می دهد.

تمام فایل های این پروژه در مخزن GitHub من ذخیره می شود: https://github.com/sahibgasimov/ecs-gitlab-terraform

در این آموزش، نحوه استقرار یک برنامه پایتون در AWS ECS Fargate را به همراه اتوماسیون زیرساخت Terraform و GitLab CI/CD برای استقرار مداوم به طور خودکار توضیح خواهم داد. بیایید شروع کنیم!

آنچه را پوشش خواهیم داد:

  • مروری بر معماری
  • پیش نیازها
  • راه اندازی زیرساخت با Terraform
    • ایجاد ماژول Terraform Backend
    • راه اندازی زیرساخت شبکه
    • ایجاد زیرساخت ECS
  • پیکربندی GitLab CI/CD
  • استقرار در توسعه و تولید

در پایان این راهنما، شما یک خط لوله کاملاً خودکار آماده برای استقرار برنامه‌های کانتینری در محیط‌های توسعه‌دهنده و پرود خواهید داشت.

معماری پروژه:

  1. AWS ECS Fargate: برای میزبانی خدمات کانتینری.
  2. Terraform: تامین زیرساخت.
  3. GitLab CI/CD: خطوط لوله ساخت، آزمایش و استقرار را مدیریت می کند.
  4. شبکه: VPC ایزوله با زیرشبکه های عمومی/خصوصی.
  5. Load Balancer: برنامه Load Balancer (ALB) برای مسیریابی ترافیک.
  6. پشتیبانی TLS: راه اندازی HTTPS با ACM و Route 53.

پیش نیازها
قبل از وارد شدن به تنظیمات، مطمئن شوید که:

  • AWS CLI نصب و پیکربندی شد.
  • Terraform (نسخه 1.6.0 یا بالاتر).
  • حساب GitLab با مجوزهای کافی.
  • داکر برای ساخت های محلی نصب شده است.

نمودار بالا هدف پروژه را نشان می دهد. اساسا ما کد منبع برنامه خود را در GitLab و همچنین دو شاخه DEV و PROD خواهیم داشت. هر بار که ما به شعبه مربوطه فشار می دهیم، اتوماسیون CI/CD جای خود را می گیرد.
بیا برویم

راه اندازی زیرساخت

ما می‌خواهیم یک ماژول پشتیبان terraform جداگانه ایجاد کنیم که در نهایت فایل حالت terraform کل پروژه در آن ذخیره می‌شود.

مرحله 1: Repository را کلون کنید

git clone https://github.com/sahibgasimov/ecs-gitlab-terraform.git
cd ecs-gitlab-terraform
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

درخت ساختار پوشه های Github:

├── backend/           # Terraform backend module
├── networking/        # VPC and networking module
├── ecs/               # ECS cluster and services module
├── gitlab_cicd/       # Gitlab pipeline file 
├── images/            # Architecture and CI/CD images
├── app/               # Python application code
├── .gitlab-ci.yml     # GitLab CI/CD pipeline
└── README.md          # Project documentation
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مرحله 2: Terraform Backend را راه اندازی کنید
این پروژه از یک سطل S3 برای مدیریت حالت Terraform و DynamoDB برای قفل استفاده می کند.

بلوک زیر را در main.tf کامنت کنید و terraform application را برای ایجاد ماژول backend اجرا کنید. پس از ایجاد به روز رسانی با سطل s3 موجود خود برای انتقال فایل حالت به سطل s3.

terraform {
  backend "s3" {
    bucket         = "my-project-terraform-state-prod"  # Replace with your S3 bucket name
    key            = "backend/terraform.tfstate"      
    region         = "us-east-1"                      
    dynamodb_table = "my-project-terraform-lock"       
    encrypt        = true
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

دستورات Terraform را برای مقداردهی اولیه و اعمال پیکربندی اجرا کنید:

terraform init
terraform apply
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون می‌توانید نظر را لغو کنید و فایل حالت را به باطن S3 منتقل کنید:

terraform init -migrate-state
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توضیحات تصویر

Terraform Backend اکنون آماده است!

شبکه سازی

ماژول VPC برای ECS Cluster

این ماژول یک AWS Virtual Private Cloud (VPC) را برای خوشه ECS، شامل زیرشبکه های خصوصی و عمومی، مسیرهای دروازه NAT برای زیرشبکه خصوصی و دروازه اینترنت برای زیرشبکه عمومی پیکربندی می کند.

توضیحات تصویر

VPC با بلوک CIDR 10.0.0.0/16، شامل زیرشبکه های عمومی و خصوصی در مناطق در دسترس. Internet Gateway و NAT Gateway به ترتیب برای دسترسی به اینترنت خروجی از زیر شبکه های عمومی و خصوصی فعال هستند.
پیش نیازها شامل پیکربندی یک سطل S3 و جدول DynamoDB برای وضعیت Terraform و تنظیم اعتبار AWS برای منطقه مشخص شده است.

cd networking/
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

terraform {
  backend "s3" {
    bucket         = "my-project-terraform-state-prod"  # Replace with your actual bucket name
    key            = "networking/terraform.tfstate"    # Unique state file key for networking module
    region         = "us-east-1"                       # Replace with your AWS region
    dynamodb_table = "my-project-terraform-lock"       # Replace with your actual DynamoDB table name
    encrypt        = true
  }
}

terraform init
terraform apply

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توضیحات تصویر

اکنون که VPC و منابع شبکه مرتبط ایجاد شده‌اند، می‌خواهیم قسمت ECS را ادامه دهیم.

توضیحات تصویر

زیرساخت ECS

برای شروع فرآیند استقرار برنامه، ما البته نیاز داریم که خوشه ECS Fargate ایجاد شود، اما حتی قبل از آن باید تصاویر داکر خود را به ECR فشار دهیم، بنابراین با ایجاد مخزن تصویر AWS ECR به صورت دستی شروع می کنیم، سپس تصویر را می سازیم و فشار می دهیم. و سپس می توانیم آن را به terraform وارد کنیم. به سادگی به کنسول AWS ECR بروید و یک مخزن خصوصی ECR ایجاد کنید. برای این آموزش نام آن را “web-app-repository” می گذاریم.
سپس در پوشه ECS سی دی قرار دهید و تصویر داکر جدید بسازید:

cd ecs/docker_dev (then docker_prod folder)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Dockerfile را بسازید تا تصویر داکر را برای محیط های DEV و PROD بسازید و سپس تصاویر را به مخزن ECR خود فشار دهید. از دستورالعمل ها در کنسول AWS ECR استفاده کنید:

توضیحات تصویر

این دستورات را برای PROD اجرا کنید:

aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 1234567.dkr.ecr.us-east-1.amazonaws.com
docker build -t web-app .

docker tag web-app:latest 1234567.dkr.ecr.us-east-1.amazonaws.com/web-app-repository:main-latest

docker push 124567.dkr.ecr.us-east-1.amazonaws.com/web-app-repository:main-latest

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همین کار را برای DEV انجام دهید:

cd ../docker_dev/

aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 1234567.dkr.ecr.us-east-1.amazonaws.com

docker build -t web-app .

docker tag web-app:latest 1234567.dkr.ecr.us-east-1.amazonaws.com/web-app-repository:dev-latest

docker push 1234567.dkr.ecr.us-east-1.amazonaws.com/web-app-repository:dev-latest
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

به پوشه ecs برگردید، provider.tf خود را با سطل backend s3 برای ecs خود به‌روزرسانی کنید و از داده‌های شبکه state backend استفاده کنید تا به صورت پویا از اجزای شبکه مانند vpc، subnets و غیره استفاده کنید.
provider.tf

terraform {
  required_version = ">= 1.6.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.73.0"
    }

    random = {
      source  = "hashicorp/random"
      version = "~> 3.6.0"
    }
  }

  backend "s3" {
    bucket         = "my-project-terraform-state-prod" # Replace with your S3 bucket name
    key            = "ecs/terraform.tfstate"           # Unique key for ECS state file
    region         = "us-east-1"                       # Replace with your AWS region
    dynamodb_table = "my-project-terraform-lock"       # Replace with your DynamoDB table name
    encrypt        = true
  }
}

provider "aws" {
  region = var.region

  # Optional: Default tags that will be applied to all resources
}

data "terraform_remote_state" "vpc" {
  backend = "s3"
  config = {
    bucket         = "my-project-terraform-state-prod" # Replace with your S3 bucket name
    key            = "networking/terraform.tfstate"    # Path to the networking state file
    region         = "us-east-1"                       # Replace with your AWS region
    dynamodb_table = "my-project-terraform-lock"       # Replace with your DynamoDB table name
    encrypt        = true
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس از پیکربندی باطن، مقادیر حساب خود را در terraform.tfvars به ​​روز کنید

# Environment and Region
env_name_prod = "prod"
env_name_dev  = "dev"       # Change to "prod" for production
region        = "us-east-1" # AWS region

# Application Details
app_name = "web-app" # Your application name

# AWS Account Details
account_id = "12345678" # Your AWS account ID

# ALB Configuration
alb_hostname_dev  = "web-app-dev.12345678.realhandsonlabs.net"
alb_hostname_prod = "web-app-prod.12345678.realhandsonlabs.net"

# Subnet and VPC IDs

route53_zone_id = "Z07843433K5DR356RSU8Z"
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای ایجاد تمامی زیرساخت ها، terraform application را اجرا کنید.

توضیحات تصویر

راه اندازی GitLab CI/CD

برای جزئیات بیشتر ساختار پوشه gitlab_cicd را بررسی کنید:
توضیحات تصویر

درخت ساختار پوشه Gitlab شما در نهایت باید به این شکل باشد

توضیحات تصویر

ما یک خط لوله GitLab CI/CD را از ابتدا ایجاد خواهیم کرد تا استقرار خودکار در AWS ECS Fargate را با استفاده از کانتینرهای Docker، AWS ECR برای ذخیره‌سازی تصویر و GitLab YAML برای پیکربندی بسازیم.

ساختار خط لوله: دو شاخه (dev و prod) به صورت پویا سرویس/وظیفه ECS هدف را بر اساس نام محیط تعریف می کنند و برنامه را مستقر می کنند. مراحل: اعتبارسنجی، ساخت، فشار و استقرار را از طریق مراحل تعریف شده CI/CD به صورت خودکار انجام دهید.

کاربر GitLab IAM

  1. یک کاربر IAM ایجاد کنید 'gitlab-cicd' مجوزهای زیر را بدهید. این کاربر تنها به دسترسی به کنسول برنامه‌ریزی شده نیاز ندارد. کلیدهای دسترسی و مخفی را برای این کاربر ایجاد کنید.

توضیحات تصویر

  1. به حساب Gitlab خود وارد شوید و یک پروژه جدید ایجاد کنید

توضیحات تصویر

  1. وارد ترمینال لینوکس خود شوید و git initialize new repository

توضیحات تصویر

  1. شما باید دو شاخه 'dev' و 'main' ایجاد کنید:

توضیحات تصویر

از هر دو شاخه خود در برابر حذف و همچنین فشار بدون ادغام محافظت کنید

توضیحات تصویر

3 متغیر را برای خط لوله خود تنظیم کنید، متغیرهای زیر را در تنظیمات GitLab CI/CD اضافه کنید:

AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_DEFAULT_REGION

توضیحات تصویر

توضیحات تصویر

راه اندازی خطوط لوله

می توانید تمام فایل های CI/CD را از مخزن gitlab من https://gitlab.com/sahib.gasimov2/gitlabcicd-ecs کپی کنید.

فایل gitlab-ci.yml کل خط لوله را برای استقرار یک برنامه وب در AWS ECS خودکار می کند. این محیط را تأیید می‌کند، تصاویر Docker را می‌سازد و به AWS ECR می‌فرستد، و در سرویس‌های ECS مستقر می‌شود (شاخه توسعه خودکار مستقر می‌شود، شعبه اصلی برای تولید به تأیید دستی نیاز دارد). از متغیرهای محیطی برای انعطاف‌پذیری استفاده می‌کند و به‌روزرسانی‌های ECS را با استقرارهای جدید اجباری برای محیط‌های توسعه‌دهنده و پرود ادغام می‌کند.

AWS_ACCOUNT_NUMBER و REGION را با مقادیر خود به‌روزرسانی کنید.

stages:
    - validate_environment
    - build_and_publish
    - deploy_to_dev
    - deploy_to_production    
    - finalize_pipeline

workflow:  # Trigger pipeline only for specific branches
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
    - if: '$CI_COMMIT_BRANCH == "dev"'

image: registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest

variables:
  AWS_ACCOUNT_NUMBER : "1245678" #update with your account number
  REGION             : "us-east-1" #update with your region 
  IMAGE_REPOSITORY   : "web-app-repository"
  CLUSTER_NAME       : "web-app-cluster" 

  DEV_SERVICE_NAME   : "web-app-dev" 
  DEV_TASK_NAME      : "web-app-dev"

  PROD_SERVICE_NAME  : "web-app-prod"
  PROD_TASK_NAME     : "web-app-prod"

test_environment:
  stage: validate_environment
  script:
    - echo "Validating environment setup..."
    - aws --version
    - docker --version
    - jq --version
    - aws sts get-caller-identity  

build_and_push:
  stage: build_and_publish
  services:
    - docker:dind
  variables:
    DOCKER_HOST: tcp://docker:2375  
  before_script:
   - aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_NUMBER.dkr.ecr.$REGION.amazonaws.com

  script:
    - echo "Building the Docker image..."
    - docker build -t $IMAGE_REPOSITORY .
    - echo "Tagging the image..."
    - docker tag $IMAGE_REPOSITORY:latest $AWS_ACCOUNT_NUMBER.dkr.ecr.$REGION.amazonaws.com/$IMAGE_REPOSITORY:$CI_COMMIT_BRANCH-latest
    - docker tag $IMAGE_REPOSITORY:latest $AWS_ACCOUNT_NUMBER.dkr.ecr.$REGION.amazonaws.com/$IMAGE_REPOSITORY:$CI_COMMIT_BRANCH-$CI_COMMIT_SHORT_SHA
    - echo "Pushing the image to ECR..."
    - docker push $AWS_ACCOUNT_NUMBER.dkr.ecr.$REGION.amazonaws.com/$IMAGE_REPOSITORY:$CI_COMMIT_BRANCH-latest
    - docker push $AWS_ACCOUNT_NUMBER.dkr.ecr.$REGION.amazonaws.com/$IMAGE_REPOSITORY:$CI_COMMIT_BRANCH-$CI_COMMIT_SHORT_SHA

deploy_to_dev:
  stage: deploy_to_dev
  rules:
    - if: '$CI_COMMIT_BRANCH == "dev"'
  script:
    - echo "Deploying to development environment..."
    - |
      aws ecs update-service \
        --cluster         $CLUSTER_NAME \
        --service         $DEV_SERVICE_NAME \
        --task-definition $DEV_TASK_NAME \
        --force-new-deployment

deploy_to_production:
  stage: deploy_to_production
  when: manual                                  # Require manual confirmation for production
  manual_confirmation: 'Proceed with production deployment?' 
  allow_failure: false                          # Must succeed to continue
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
  script:
    - echo "Deploying to production environment..."
    - |
      aws ecs update-service \
        --cluster         $CLUSTER_NAME \
        --service         $PROD_SERVICE_NAME \
        --task-definition $PROD_TASK_NAME \
        --force-new-deployment        

finalize_pipeline:
  stage: finalize_pipeline
  script:
    - echo "CI/CD Pipeline completed successfully!"
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس از ایجاد یک شاخه و ادغام تغییر به توسعه دهنده یا شاخه اصلی، شاخه خط لوله را راه اندازی می کند و برنامه را اجرا و به روز می کند.

توضیحات تصویر

توضیحات تصویر

برنامه پایتون و داکرفایل

من از یک برنامه ساده پایتون برای این نسخه آزمایشی استفاده خواهم کرد که به سادگی تصویر را به PDF تبدیل می کند.

from flask import Flask, request, send_file, jsonify
from PIL import Image
import os

app = Flask(__name__)
UPLOAD_FOLDER = 'uploads'
OUTPUT_FOLDER = 'output'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(OUTPUT_FOLDER, exist_ok=True)

@app.route('/')
def home():
    return '''
    
    Image to PDF Converter
    
    
    '''

@app.route('/convert', methods=['POST'])
def convert_to_pdf():
    if 'image' not in request.files:
        return "No file uploaded", 400

    file = request.files['image']
    if file.filename == '':
        return "No selected file", 400

    try:
        # Save the uploaded file
        image_path = os.path.join(UPLOAD_FOLDER, file.filename)
        file.save(image_path)

        # Convert to PDF
        image = Image.open(image_path)
        if image.mode != 'RGB':
            image = image.convert('RGB')
        pdf_path = os.path.join(OUTPUT_FOLDER, f"{os.path.splitext(file.filename)[0]}.pdf")
        image.save(pdf_path, "PDF")

        # Send the PDF file as a response
        return send_file(pdf_path, as_attachment=True)
    except Exception as e:
        return f"An error occurred: {e}", 500

# Health check endpoint for ALB
@app.route('/api/health', methods=['GET'])
def health_check():
    return jsonify({"status": "healthy"}), 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080, debug=True)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Dockerfile

# Use an official Python runtime as the base image
FROM python:3.9-slim

# Set the working directory in the container
WORKDIR /app

# Copy the application code and requirements into the container
COPY . /app

# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt

# Expose port 8080 for the Flask application
EXPOSE 8080

# Run the Flask application
CMD ["python", "app.py"]
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

از پروژه خود لذت ببرید!

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا