Blue/Green Type Build Files

Hoju·2022년 8월 25일
0
post-custom-banner
  • Buildspec.yml 정식 - 사용자에 맞게 수정
version: 0.2

env:
  exported-variables: #내보낼 환경 변수 지정합니다.
    - AWS_DEFAULT_REGION

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws --version
      - aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.ap-northeast-2.amazonaws.com
      - REPOSITORY_URI=$AWS_ACCOUNT_ID.dkr.ecr.ap-northeast-2.amazonaws.com/wsi-fargate-ecr-repo
      - 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:
      - docker push $REPOSITORY_URI\:latest
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - echo Writing image definitions file...
      - printf '[{"name":"wsi-rolling-deploy","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
      - printf '{"ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json
artifacts:
    files:
      - imagedefinitions.json
      - imageDetail.json
      - appspec.yml
      - taskdef.json
    secondary-artifacts:
      DefinitionArtifact:
        files:
          - appspec.yml
          - taskdef.json
      ImageArtifact:
        files:
          - imageDetail.json
  • Buildspec.yml > Build ID로 Dockerimage Tag
version: 0.2
phases:
  pre_build:
    commands:
      - echo $AWS_DEFAULT_REGION
      - aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.ap-northeast-2.amazonaws.com
      - REPOSITORY_NAME="wsi-ecr-repo"
      - REPOSITORY_URI=$AWS_ACCOUNT_ID.dkr.ecr.ap-northeast-2.amazonaws.com/$REPOSITORY_NAME
      - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
      - IMAGE_TAG=${COMMIT_HASH:=latest}
  build:
    commands:
      - echo Building the Docker image...
      - docker build -t wsi-ecr-repo:latest .
      - docker tag wsi-ecr-repo:latest $AWS_ACCOUNT_ID.dkr.ecr.ap-northeast-2.amazonaws.com/wsi-ecr-repo:latest
      - docker tag $REPOSITORY_NAME:latest $REPOSITORY_URI:$IMAGE_TAG
  post_build:
    commands:
      - docker push $REPOSITORY_URI:latest
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - printf '[{"name":"golang-container","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
      - OLD=$AWS_ACCOUNT_ID.dkr.ecr.ap-northeast-2.amazonaws.com/eks-ecr-repo:7808f41
      - ECRREPO=$REPOSITORY_URI:$IMAGE_TAG
      - sed -i "s|$OLD|$ECRREPO|g" taskdefintion.json
      - sed -i s/AWS_DEFAULT_REGION/$AWS_DEFAULT_REGION/ appspec.yaml 
      - sed -i s/AWS_ACCOUNT_ID/$AWS_ACCOUNT_ID/ appspec.yaml 
      - sed -i s/TASK_NAME/$TASK_NAME/ appspec.yaml 
      - sed -i s/CONTAINER_NAME/$CONTAINER_NAME/ appspec.yaml 
      - sed -i s/CONTAINER_PORT/$CONTAINER_PORT/ appspec.yaml
artifacts:
  files:
    - imagedefinitions.json
    - imagedefinitions.json
    - appspec.yml
    - taskdefintion.json
  • Buildspec.yml > dateTime로 DockerImage Tag
version: 0.2
phases:
  pre_build:
    commands:
      - echo $AWS_DEFAULT_REGION
      - aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 680360122082.dkr.ecr.ap-northeast-2.amazonaws.com
      - REPOSITORY_NAME="wsi-ecr-repo"
      - REPOSITORY_URI=680360122082.dkr.ecr.ap-northeast-2.amazonaws.com/$REPOSITORY_NAME
      - COMMIT_HASH=$(date +"%y%m%d%H%M%S")
      - IMAGE_TAG=${COMMIT_HASH:=latest}
  build:
    commands:
      - echo Building the Docker image...
      - docker build -t wsi-ecr-repo:latest .
      - docker tag wsi-ecr-repo:latest 680360122082.dkr.ecr.ap-northeast-2.amazonaws.com/wsi-ecr-repo:latest
      - docker tag $REPOSITORY_NAME:latest $REPOSITORY_URI:$IMAGE_TAG
  post_build:
    commands:
      - docker push $REPOSITORY_URI:latest
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - printf '[{"name":"golang-container","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
      - OLD=680360122082.dkr.ecr.ap-northeast-2.amazonaws.com/eks-ecr-repo:7808f41
      - ECRREPO=$REPOSITORY_URI:$IMAGE_TAG
      - sed -i "s|$OLD|$ECRREPO|g" taskdefintion.json
      - sed -i s/AWS_DEFAULT_REGION/$AWS_DEFAULT_REGION/ appspec.yaml 
      - sed -i s/AWS_ACCOUNT_ID/$AWS_ACCOUNT_ID/ appspec.yaml 
      - sed -i s/TASK_NAME/$TASK_NAME/ appspec.yaml 
      - sed -i s/CONTAINER_NAME/$CONTAINER_NAME/ appspec.yaml 
      - sed -i s/CONTAINER_PORT/$CONTAINER_PORT/ appspec.yaml
artifacts:
  files:
    - imagedefinitions.json
    - appspec.yml
    - taskdefintion.json

Buildspec.yml 파일을 구성하실 때 꼭!!! 열을 제대로 맞춰야합니다. 구문이 조금이라도 틀리면 에러가 발생합니다.

  • appspec.yml(기본) - 사용자에 맞게 수정
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: "wsi-fargate-containers"
          ContainerPort: 8080
  • appspec.yml(용량 공급자 옵션 추가)
version: 0.0 
Resources: 
  - TargetService: 
      Type: AWS::ECS::Service 
      Properties: 
        TaskDefinition: "arn:aws:ecs:AWS_DEFAULT_REGION:AWS_ACCOUNT_ID:task-definition/TASK_NAME" 
        LoadBalancerInfo: 
          ContainerName: "CONTAINER_NAME"
          ContainerPort: CONTAINER_PORT
	PlatformVersion: "LATEST"
	NetworkConfiguration:
          AwsvpcConfiguration:
            Subnets: ["subnet-1234abcd","subnet-5678abcd"]
            SecurityGroups: ["sg-12345678"]
            AssignPublicIp: "DISABLED"
	CapacityProviderStrategy:
          - Base: 1 #Base는 용량 공급자에서 실행할 테스크 수를 지정합니다.
            CapacityProviderA: "FARGATE_SPOT"
            Weight: 1 #capacityProviderA에 1의 가중치를 지정하고 capacityProviderB에 4의 가중치를 지정하면 capacityProviderA를 사용하여 실행되는 모든 태스크에 대해 네 가지 태스크에서 capacityProviderB를 사용합니다.
          - Base: 0
            CapacityProviderB: "FARGATE"
            Weight: 4

ECS Cluster를 Fargate 유형을 생성하면 용량 공급자가 2개가 기본적으로 생성됩니다

  • taskdefintion.json - 사용자에 맞게 수정
{
  "family": "wsi-bluegreen-fargate-df",
  "executionRoleArn": "arn:aws:iam::040217728499:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::040217728499:role/ecsTaskExecutionRole",
  "networkMode": "awsvpc",
  "memory": "1024",
  "cpu": "512",
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "containerDefinitions": [
    {
      "name": "wsi-fargate-containers",
      "memoryReservation": 500,
      "image": "<IMAGE_NAME>",
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/wsi-bluegreen-fargate-df",
          "awslogs-region": "ap-northeast-2",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "portMappings": [
        {
          "hostPort": 8080,
          "protocol": "tcp",
          "containerPort": 8080
        }
      ],
      "essential": true
    }
  ]
}

JSON은 주석을 허용하지 않기때문에 여기에 JSON에서 중요한 점을 명시하도록 하겠습니다.
Role을 꼭 지정해합니다. 또한 LogGroup이 존재해야합니다.
또한 현재 Image는 <IMAGE_NAME>으로 지정했습니다. Pipeline에서 Blue/Green 배포할 때 왜 해주었는지 알게될 수 있습니다.

EC2 Taskdef.json

{
  "family": "wsi-ecs-ec2-tf",
  "networkMode": "bridge",
  "memory": "256",
  "executionRoleArn": "arn:aws:iam::040217728499:role/ecsTaskExecutionRole",
  "requiresCompatibilities": [
    "EC2"
  ],
  "containerDefinitions": [
    {
      "name": "wsi-ec2-containerimages",
      "image": "<IMAGE_NAME>",
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/wsi-ecs-ec2-tf",
          "awslogs-region": "ap-northeast-2",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "portMappings": [
        {
          "hostPort": 0,
          "protocol": "tcp",
          "containerPort": 8080
        }
      ],
      "essential": true
    }
  ]
}
  • Golang Application File
package main

import (
	"fmt"
	"log"
	"net"
	"net/http"
)

func main() {
	log.Print("HTTPserver: Enter main()")
	http.HandleFunc("/health", handler)
	log.Fatal(http.ListenAndServe("0.0.0.0:8080", nil))
}

// printing request headers/params
func handler(w http.ResponseWriter, r *http.Request) {

	log.Print("request from address: %q\n", r.RemoteAddr)
	fmt.Fprintf(w, "%s %s %s\n", r.Method, r.URL, r.Proto)

	fmt.Fprintf(w, "Host = %q\n", r.Host)
	fmt.Fprintf(w, "RemoteAddr = %q\n", r.RemoteAddr)
	if err := r.ParseForm(); err != nil {
		log.Print(err)
	}
	for k, v := range r.Form {
		fmt.Fprintf(w, "Form[%q] = %q\n", k, v)
	}
	fmt.Fprintf(w, "\n===> local IP: %q\n\n", GetOutboundIP())
}

func GetOutboundIP() net.IP {
	conn, err := net.Dial("udp", "8.8.8.8:80")
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	localAddr := conn.LocalAddr().(*net.UDPAddr)

	return localAddr.IP
}
  • Dockerfile
cat << EOF > Dockerfile
FROM golang:alpine AS builder

ENV GO111MODULE=on \
    CGO_ENABLED=0 \
    GOOS=linux \
    GOARCH=amd64
WORKDIR /build
COPY ./HTTPserver.go .

# Build the application
RUN go build -o HTTPserver ./HTTPserver.go
WORKDIR /dist
RUN cp /build/HTTPserver .

# Build a small image
FROM scratch
COPY --from=builder /dist/HTTPserver /
EXPOSE 8080
ENTRYPOINT ["/HTTPserver"]
EOF
profile
Devops가 되고 싶은 청소년
post-custom-banner

0개의 댓글