برنامه نویسی

استقرار آبی/سبز در نمونه های AWS EC2 با دفترچه اتوماسیون مدیر سیستم

مقدمه:

استراتژی استقرار آبی/سبز در این پست بر اساس این پست AWS در مورد استقرار دقیق آبی/سبز در تعادل بار برنامه است. اما چرا این راه حل به جای استفاده از CodeDeploy است؟

در مورد ما ، ما باید ترافیک فوری از محیط “سبز” به “آبی” ، CodedePloy ، در حال حاضر ، این گزینه را برای سکوی محاسبه EC2/On-Premises ، حتی با گزینه “Reroute Traffice بلافاصله” نداریم. “ما در همان زمان از نمونه های” سبز “و” آبی “EC2 برای مدتی در طی فرآیندهای استقرار پاسخی داریم.

مسئله دیگر این است که استقرار CodeDeploy در پلت فرم محاسبه EC2/On-Premises بر اساس برچسب های موارد استوار است ، پس از فرآیند استقرار ، ما باید راه حلی برای مدیریت برچسب ها در نمونه “آبی” داشته باشیم تا برای استقرار بعدی آماده شویم.

همچنین ، مشکلی در ایجاد پیکربندی لازم از گروه استقرار CodedePloy با CloudFormation وجود دارد (CloudFormation برای ایجاد زیرساخت ها در AWS استفاده می شود).

دفترچه اتوماسیون Systems Manager می تواند در پیکربندی استقرار مربوط به نیازهای ما انعطاف پذیرتر باشد.

این پست اولین بخش از سری پست های من در مورد استقرار آبی/سبز در موارد AWS EC2 با کتاب AUTOMATION SYSTEMS Manager است ، قسمت دوم اینجا است و قسمت سوم در اینجا است.

درباره پروژه:

کلیه زیرساخت ها در AWS (به جز S3 سطل ، دامنه مسیر 53 و گواهی SSL/TLS) برای این پروژه با CloudFormation ایجاد شده و در این مخزن قابل یافت است. سطل S3 برای ذخیره الگوهای پشته تو در تو و پرونده های برنامه ضروری است. مسیر 53 دامنه و گواهی SSL/TLS برای دسترسی ایمن وب به موارد EC2 از طریق متعادل کننده بار برنامه ضروری است. موضوع SNS آمازون برای ارسال اعلان ها در مورد وضعیت استقرار ضروری است.

مراحل اصلی RUNBOOK AUTOMATION SYSTEMS:

الف) بررسی اینکه آیا ما قبلاً اعدام مربوط به دفترچه را داریم ، اگر بله – از استقرار پرش کنید.

ب) ایجاد یک نمونه EC2 “سبز” با تمام پیکربندی های لازم ، چند دقیقه منتظر برای اطمینان از تنظیم صحیح همه چیز است.

ج) ساخت مجدد از نمونه و بررسی وضعیت نمونه پس از راه اندازی مجدد.

د) استقرار نمونه EC2 “سبز”: ثبت نمونه برای گروه هدف لازم ، ایجاد وزنهای مبادله گروههای هدف در پیکربندی قانون شنونده ، خاتمه دادن به عنوان “آبی” EC2.

ه) ارسال اعلان در مورد وضعیت استقرار.

پیکربندی مرحله استقرار آبی/سبز از کتاب Runbook Manager Manager:

    - name: BlueGreenDeployment
      action: aws:executeScript
      maxAttempts: 2
      timeoutSeconds: 300
      isCritical: true
      onFailure: step:SendNotification
      inputs:
        Runtime: python3.8
        Handler: BlueGreenDeployment
        InputPayload:
          Region: "{{ global:REGION }}"
          ListenerArn: "{{ ListenerArn }}"
          InstanceIds: "{{ LaunchInstance.CreatedInstanceId }}"
        Script: |
          import boto3
          import time
          from botocore.exceptions import ClientError

          def BlueGreenDeployment(event, context):
              try:
                  elbv2 = boto3.client('elbv2', region_name=event['Region'])
                  ec2_client = boto3.client('ec2', region_name=event['Region'])

                  # Register instance with the target group
                  chosen_target_group, target_group_arn_1, target_group_arn_2, instances_tg1, instances_tg2, weight_tg1, weight_tg2 = get_listener_details(elbv2, event['ListenerArn'])

                  if chosen_target_group is None:
                      raise Exception("[ERROR] We don't have necessary target group.")

                  elbv2.register_targets(
                      TargetGroupArn=chosen_target_group,
                      Targets=[
                          {'Id': instance_id}
                          for instance_id in event['InstanceIds']
                      ],
                  )
                  print(f"[INFO] Instance {event['InstanceIds']} registered with the target group {chosen_target_group}")

                  # Wait for instances to be healthy
                  wait_for_instances_to_be_healthy(elbv2, chosen_target_group, event['InstanceIds'], max_wait_time=300)

                  if instances_tg1 or instances_tg2:
                      swap_weights(elbv2, event['ListenerArn'], target_group_arn_1, target_group_arn_2, weight_tg1, weight_tg2)

                      time.sleep(15)

                      # Terminate "Blue" instance
                      if instances_tg1:
                          for instance_id in instances_tg1:
                              if instance_id not in instances_tg2 and weight_tg1 == 100:
                                  ec2_client.terminate_instances(InstanceIds=[instance_id])
                                  print(f"Instance {instance_id}  terminated from Target Group 1")
                      if instances_tg2:
                          for instance_id in instances_tg2:
                              if instance_id not in instances_tg1 and weight_tg2 == 100:
                                  ec2_client.terminate_instances(InstanceIds=[instance_id])
                                  print(f"Instance {instance_id}  terminated from Target Group 2")
                      print("[INFO] Traffic swap and EC2 instance termination completed successfully.")
                  else:
                      print("[INFO] Traffic swap and EC2 instance termination were skipped")
              except ClientError as e:
                  raise Exception("[ERROR]", e)

          # get ARNs of target groups and weights of this groups in Listener rule
          def get_listener_details(elb_client, listener_arn):
              # Get the current state of the listener and its rules
              listener_description = elb_client.describe_rules(ListenerArn=listener_arn)

              # Get the Target Group ARNs and weights from the listener rule
              target_group_arn_1 = listener_description['Rules'][0]['Actions'][0]['ForwardConfig']['TargetGroups'][0]['TargetGroupArn']
              target_group_arn_2 = listener_description['Rules'][0]['Actions'][0]['ForwardConfig']['TargetGroups'][1]['TargetGroupArn']
              weight_tg1 = listener_description['Rules'][0]['Actions'][0]['ForwardConfig']['TargetGroups'][0]['Weight']
              weight_tg2 = listener_description['Rules'][0]['Actions'][0]['ForwardConfig']['TargetGroups'][1]['Weight']

              # Get instance IDs from target groups
              instances_tg1 = get_instance_ids(elb_client, target_group_arn_1)
              instances_tg2 = get_instance_ids(elb_client, target_group_arn_2)

              # Check if instances are registered to the target groups
              if not instances_tg1 and not instances_tg2:
                  chosen_target_group = target_group_arn_2 if weight_tg2 == 100 else target_group_arn_1
              elif not instances_tg1:
                  chosen_target_group = target_group_arn_1
              elif not instances_tg2:
                  chosen_target_group = target_group_arn_2
              else:
                  chosen_target_group = None
              return chosen_target_group, target_group_arn_1, target_group_arn_2, instances_tg1, instances_tg2, weight_tg1, weight_tg2

          # Take Instances IDs registered to the Target Groups
          def get_instance_ids(elb_client, target_group_arn):
            response = elb_client.describe_target_health(TargetGroupArn=target_group_arn)
            instance_ids = [target['Target']['Id'] for target in response['TargetHealthDescriptions'] if target['TargetHealth']['State'] == 'healthy']
            return instance_ids

          def wait_for_instances_to_be_healthy(elbv2_client, target_group_arn, instance_ids, max_wait_time=300, polling_interval=10):
              start_time = time.time()

              while time.time() - start_time < max_wait_time:
                  # Describe the health of the instances in the target group
                  health_response = elbv2_client.describe_target_health(TargetGroupArn=target_group_arn)

                  # Check if all specified instances are healthy
                  healthy_instance_ids = {health['Target']['Id'] for health in health_response['TargetHealthDescriptions'] if health['TargetHealth']['State'] == 'healthy'}
                  if set(instance_ids) == healthy_instance_ids:
                      print(f"[INFO] All instances {instance_ids} are healthy in {target_group_arn}")
                      return

                  # Wait before the next check
                  time.sleep(polling_interval)

              # If the loop exits, raise an exception indicating that instances are not healthy
              raise Exception(f"[ERROR] Instances {instance_ids} in target group {target_group_arn} did not become healthy within the specified time.")

          def swap_weights(elb_client, listener_arn, target_group_arn_1, target_group_arn_2, weight_tg1, weight_tg2):
              # Swap the weights for the listener rule
              elb_client.modify_listener(
                  ListenerArn=listener_arn,
                  DefaultActions=[
                      {
                          "Type": "forward",
                          "ForwardConfig": {
                              "TargetGroups": [
                                  {
                                      "TargetGroupArn": target_group_arn_1,
                                      "Weight": weight_tg2
                                  },
                                  {
                                      "TargetGroupArn": target_group_arn_2,
                                      "Weight": weight_tg1
                                  }
                              ]
                          }
                      }
                  ]
              )
              print("Weight swap completed successfully")
      nextStep: SendNotification
حالت تمام صفحه را وارد کنید

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

طرح های استقرار و زیرساخت ها:

طرح اعزام دفترچه راهنمای مدیر سیستم

طرحواره زیرساختی

پیش نیازها:

قبل از شروع ، اطمینان حاصل کنید که شرایط زیر برآورده شده است:

  • یک حساب AWS با مجوزهای ایجاد منابع.
  • AWS CLI روی دستگاه محلی شما نصب شده است.

استقرار:

  1. مخزن را کلون کنید.
    git clone https://gitlab.com/Andr1500/ssm_runbook_bluegreen.git
حالت تمام صفحه را وارد کنید

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

  1. یک سطل S3 با یک نام منحصر به فرد برای الگوهای پشته تو در تو و پرونده های برنامه ایجاد کنید. در اینجا الزامات مربوط به قوانین نامگذاری سطل وجود دارد.
    on Linux:
    date=$(date +%Y%m%d%H%M%S)

    on Windows PowerShell:
    $date = Get-Date -Format "yyyyMMddHHmmss"

    aws s3api create-bucket --bucket cloudformation-app-files-${date} --region YOUR_REGION \
     --create-bucket-configuration LocationConstraint=YOUR_REGION
حالت تمام صفحه را وارد کنید

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

  1. برای دسترسی از نمونه EC2 به سطل S3 اضافه کنید.
    aws s3api put-bucket-policy --bucket cloudformation-app-files-${date} \
    --policy '{"Version":"2012–10–17","Statement":[{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"s3:GetObject","Resource":"arn:aws:s3:::'"cloudformation-app-files-${date}"'/*"}]}'
حالت تمام صفحه را وارد کنید

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

  1. تمام پارامترهای لازم را در پرونده زیرساخت/root.yaml پر کنید و تمام پرونده های پشته تو در تو را به سطل S3 ارسال کنید.
    aws s3 cp infrastructure s3://cloudformation-app-files-${date}/infrastructure  --recursive
حالت تمام صفحه را وارد کنید

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

  1. به فهرست زیرساخت ها بروید و پشته CloudFormation را ایجاد کنید.
    aws cloudformation create-stack \
        --stack-name ec2-bluegreen-deployment \
        --template-body file://root.yaml \
        --capabilities CAPABILITY_NAMED_IAM \
        --parameters ParameterKey=UserData,ParameterValue="$(base64 -i user_data.txt)" \
        --disable-rollback
حالت تمام صفحه را وارد کنید

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

  1. صندوق پستی خود را باز کنید و اشتراک خود را در موضوع SNS تأیید کنید. دسترسی به نمونه EC2 مستقر از طریق مدیر سیستم امکان پذیر است. به کنسول AWS بروید -> مدیر سیستم AWS -> مدیر ناوگان -> نمونه EC2 ایجاد شده -> اقدامات گره -> اتصال -> جلسه ترمینال را شروع کنید. در اینجا می توانید بررسی کنید که آیا همه چیز به درستی در طی فرآیند استقرار ایجاد شده و پیکربندی شده است یا خیر.

  2. برای استقرار دستی تمام پرونده های برنامه را به سطل S3 ارسال کنید.

    aws s3 cp application s3://cloudformation-app-files-${date}/application  --recursive
حالت تمام صفحه را وارد کنید

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

START SYSTEMS Manager Automation Runbook اجرای کتاب ، اگر همه چیز خوب است – شما با اطلاعات “وضعیت استقرار: موفقیت” ایمیلی دریافت می کنید و در صورت بروز هرگونه خرابی ، به نمونه EC2 مستقر از طریق مرورگر وب دسترسی خواهید داشت – یک ایمیل دریافت می کنید با اطلاعات “وضعیت استقرار: شکست خورده” و جزئیات مربوط به مرحله ناموفق. برای استقرار نسخه جدیدی از برنامه – تغییر در زیرساخت/index.html ایجاد کنید ، تغییراتی در سطل S3 ارسال کنید و مجدداً دفترچه اتوماسیون Systems Manager را شروع کنید.

    aws ssm start-automation-execution --document-name "Ec2BlueGreenDeployment"
حالت تمام صفحه را وارد کنید

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

  1. آزمون استقرار. در Tests/test_deployment.sh می توانید یک اسکریپت ساده برای انجام آزمایش در دسترس بودن و پاسخ از نمونه های “سبز” و “آبی” EC2 پیدا کنید.

  2. حذف همه پرونده ها از سطل S3 و حذف سطل S3.

    aws s3 rm s3://cloudformation-app-files-${date} --recursive
    aws s3 rb s3://cloudformation-app-files-${date} --force
حالت تمام صفحه را وارد کنید

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

نتیجه گیری:

در این پست ، ما نشان دادیم که چگونه می توان استقرار آبی/سبز را با ویژگی گروه هدف وزنه بردار بارگذاری بار با برنامه کاربردی با استفاده از برنامه اتوماسیون سیستم مدیریت سیستم انجام داد.

اگر این پست را مفید و جالب دیدید ، لطفاً روی دکمه واکنش زیر کلیک کنید تا پشتیبانی خود را از نویسنده نشان دهید. در صورت تمایل می توانید از این پست استفاده کنید و به اشتراک بگذارید!

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

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

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

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