ECS Codebuild CodePipeline

PHYYOU·2022년 8월 26일
0

Reference:
https://docs.aws.amazon.com/ko_kr/codepipeline/latest/userguide/tutorials-ecs-ecr-codedeploy.html#tutorials-ecs-ecr-codedeploy-loadbal
https://docs.aws.amazon.com/ko_kr/codepipeline/latest/userguide/ecs-cd-pipeline.html#cd-buildspec
https://docs.aws.amazon.com/codepipeline/latest/userguide/file-reference.html#file-reference-ecs-bluegreen
https://ecsworkshop.com/blue_green_deployments/
https://github.com/aws-containers/ecs-workshop-blue-green-deployments/tree/main/nginx-sample
https://github.com/aws-containers/ecs-workshop-blue-green-deployments/tree/main/nginx-sample
https://neo-blog.tistory.com/45

Network, VPC

충남 1과제때 했던 vpc network cloudformation 변경해서 재사용

---
AWSTemplateFormatVersion: "2010-09-09"
Description: "Amazon VPC - Private and Public subnets"

Parameters:
  VpcBlock:
    Type: String
    Default: 10.1.0.0/16
    Description: The CIDR range for the VPC. This should be a valid prviateate (RFC 1918) CIDR range.

  PublicSubnet01Block:
    Type: String
    Default: 10.1.0.0/24
    Description: CidrBlock for publiclic subnet 01 within the VPC

  PublicSubnet02Block:
    Type: String
    Default: 10.1.1.0/24
    Description: CidrBlock for publiclic subnet 02 within the VPC

  PrivateSubnet01Block:
    Type: String
    Default: 10.1.2.0/24
    Description: CidrBlock for prviateate subnet 01 within the VPC

  PrivateSubnet02Block:
    Type: String
    Default: 10.1.3.0/24
    Description: CidrBlock for prviateate subnet 02 within the VPC

  Subnet01AZ:
    Type: String
    Default: "ap-northeast-2a"

  Subnet02AZ:
    Type: String
    Default: "ap-northeast-2b"

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "Worker Network Configuration"
        Parameters:
          - VpcBlock
          - PublicSubnet01Block
          - PublicSubnet02Block
          - PrivateSubnet01Block
          - PrivateSubnet02Block

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcBlock
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-vpc"

  InternetGateway:
    Type: "AWS::EC2::InternetGateway"

  VPCGatewayAttachment:
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: Public Subnets
        - Key: Network
          Value: Public

  PrivateRouteTable01:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: Private Subnet AZ1
        - Key: Network
          Value: Private01

  PrivateRouteTable02:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: Private Subnet AZ2
        - Key: Network
          Value: Private02

  PublicRoute:
    DependsOn: VPCGatewayAttachment
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PrivateRoute01:
    DependsOn:
      - VPCGatewayAttachment
      - NatGateway01
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable01
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGateway01

  PrivateRoute02:
    DependsOn:
      - VPCGatewayAttachment
      - NatGateway02
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable02
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGateway02

  NatGateway01:
    DependsOn:
      - NatGatewayEIP1
      - PublicSubnet01
      - VPCGatewayAttachment
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt "NatGatewayEIP1.AllocationId"
      SubnetId: !Ref PublicSubnet01
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-NatGatewayAZ1"

  NatGateway02:
    DependsOn:
      - NatGatewayEIP2
      - PublicSubnet02
      - VPCGatewayAttachment
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt "NatGatewayEIP2.AllocationId"
      SubnetId: !Ref PublicSubnet02
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-NatGatewayAZ2"

  NatGatewayEIP1:
    DependsOn:
      - VPCGatewayAttachment
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: vpc

  NatGatewayEIP2:
    DependsOn:
      - VPCGatewayAttachment
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: vpc

  PublicSubnet01:
    Type: AWS::EC2::Subnet
    Metadata:
      Comment: Subnet 01
    Properties:
      MapPublicIpOnLaunch: true
      AvailabilityZone: !Ref Subnet01AZ
      CidrBlock:
        Ref: PublicSubnet01Block
      VpcId:
        Ref: VPC
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-public-a"

  PublicSubnet02:
    Type: AWS::EC2::Subnet
    Metadata:
      Comment: Subnet 02
    Properties:
      MapPublicIpOnLaunch: true
      AvailabilityZone: !Ref Subnet02AZ
      CidrBlock:
        Ref: PublicSubnet02Block
      VpcId:
        Ref: VPC
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-public-b"

  PrivateSubnet01:
    Type: AWS::EC2::Subnet
    Metadata:
      Comment: Subnet 03
    Properties:
      AvailabilityZone: !Ref Subnet01AZ
      CidrBlock:
        Ref: PrivateSubnet01Block
      VpcId:
        Ref: VPC
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-prviate-a"

  PrivateSubnet02:
    Type: AWS::EC2::Subnet
    Metadata:
      Comment: Private Subnet 02
    Properties:
      AvailabilityZone: !Ref Subnet02AZ
      CidrBlock:
        Ref: PrivateSubnet02Block
      VpcId:
        Ref: VPC
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-prviate-b"

  PublicSubnet01RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet01
      RouteTableId: !Ref PublicRouteTable

  PublicSubnet02RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet02
      RouteTableId: !Ref PublicRouteTable

  PrivateSubnet01RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet01
      RouteTableId: !Ref PrivateRouteTable01

  PrivateSubnet02RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet02
      RouteTableId: !Ref PrivateRouteTable02

Outputs:
  SubnetIds:
    Description: Subnets IDs in the VPC
    Value:
      !Join [
        ",",
        [
          !Ref PublicSubnet01,
          !Ref PublicSubnet02,
          !Ref PrivateSubnet01,
          !Ref PrivateSubnet02,
        ],
      ]

  VpcId:
    Description: The VPC Id
    Value: !Ref VPC

Bastion EC2

public 서브넷에 bastion EC2 생성
PowerUser Role 연결, docker, golang, jq, curl 설치

Task Definition

ECS의 서비스를 위해서는 컨테이너 단위인 task definition을 이용해야 한다.

taskdef.json

{
    "executionRoleArn": "arn:aws:iam::492622758225:role/ecsTaskExecutionRole",
    "containerDefinitions": [
        {
            "name": "sample-website",
            "image": "492622758225.dkr.ecr.ap-northeast-2.amazonaws.com/wsi-api-ecr:latest",
            "essential": true,
            "portMappings": [
                {
                    "hostPort": 80,
                    "protocol": "tcp",
                    "containerPort": 3000
                }
            ]
        }
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "networkMode": "awsvpc",
    "cpu": "256",
    "memory": "512",
    "family": "wsi-api"
}

위 파일을 만들고 ecs task definition에 등록시킨다
aws ecs register-task-definition --cli-input-json file://taskdef.json

ECS 생성

ECS를 생성한다.

ECS Task Execution Role도 자동생성

태스크가 이미 정의되어 있으니 그걸 기준으로 서비스를 만든다.

ECS 생성할 때 예전 콘솔로 할것!!!

ECS Deployment 옵션이 신규 콘솔에는 롤링 업데이트만 선택가능함!!!

CodeCommit

  • wsi api 레포지토리 생성

  • bastion ec2에 go 설치 후

  • 지금은 배포파일이 없으니 대충 만든 go 애플리케이션 생성 및 의존성 설치 main.go go mod init wsi-api, go mod tidy 명령어로 수행 (go.mod go.sum 파일 생성됨)

    		package main
    	
    		import (
    		        "github.com/gin-gonic/gin"
    		)
    	
    		func main() {
    		        gin.SetMode(gin.ReleaseMode)
    		        r := gin.Default()
    		        r.GET("/ping", func(c *gin.Context) {
    		                c.JSON(200, gin.H{
    		                        "message": "pong",
    		                })
    		        })
    		        r.Run(":3000") // port
    		}
    		```
  • 다음 도커파일 생성

    FROM golang:alpine AS builder
    
    ENV GO111MODULE=on \
      CGO_ENABLED=0 \
      GOOS=linux \
      GOARCH=amd64
    
    WORKDIR /build
    
    COPY go.mod go.sum main.go ./
    
    RUN go mod download
    
    RUN go build -o main .
    
    WORKDIR /dist
    
    RUN cp /build/main .
    
    FROM scratch
    
    COPY --from=builder /dist/main .
    
    ENTRYPOINT ["/main"]
  • buildspec.yml

    	```yaml
    	version: 0.2
    
    	phases:
    	  pre_build:
    	    commands:
    	      - echo Logging in to Amazon ECR...
    	      - aws --version
    	      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin 012345678910.dkr.ecr.us-west-2.amazonaws.com
    	      - REPOSITORY_URI=012345678910.dkr.ecr.us-west-2.amazonaws.com/wsi-ecr
    	      - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
    	      - IMAGE_TAG=${COMMIT_HASH:=latest}
    	  build:
    	    commands:
    	      - echo Build started on `date`
    	      - echo Building the Docker image...
    	      - docker build -t $REPOSITORY_URI:latest .
    	      - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
    	  post_build:
    	    commands:
    	      - echo Build completed on `date`
    	      - echo Pushing the Docker images...
    	      - docker push $REPOSITORY_URI:latest
    	      - docker push $REPOSITORY_URI:$IMAGE_TAG
    	      - echo Writing image definitions file...
    	      - printf '[{"name":"wsi-ecr","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
    	artifacts:
    	    files: imagedefinitions.json
    	```
  • taskdef.json

{
    "containerDefinitions": [
        {
            "name": "sample-website",
            "image": "492622758225.dkr.ecr.ap-northeast-2.amazonaws.com/wsi-api-ecr:IMAGE_TAG",
            "essential": true,
            "portMappings": [
                {
                    "hostPort": 80,
                    "protocol": "tcp",
                    "containerPort": 80
                }
            ]
        }
    ],
    "executionRoleArn": "arn:aws:iam::492622758225:role/ecsTaskExecutionRole",
    "taskRoleArn": "arn:aws:iam::492622758225:role/ecsTaskExecutionRole",
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "networkMode": "awsvpc",
    "cpu": "256",
    "memory": "512",
    "family": "wsi-api"
}
  • appspec.yaml
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: "wsi-api"
          ContainerPort: 80
profile
박효영

0개의 댓글