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
충남 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
public 서브넷에 bastion EC2 생성
PowerUser Role 연결, docker, golang, jq, curl 설치
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 Task Execution Role도 자동생성
태스크가 이미 정의되어 있으니 그걸 기준으로 서비스를 만든다.
ECS 생성할 때 예전 콘솔로 할것!!!
ECS Deployment 옵션이 신규 콘솔에는 롤링 업데이트만 선택가능함!!!
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"
}
version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: <TASK_DEFINITION>
LoadBalancerInfo:
ContainerName: "wsi-api"
ContainerPort: 80