Chapter2. 데브옵스 파이프라인 구축

Glen·2023년 9월 26일
0

1. Circle Ci

  • ci 진행하기 위한 github와 연동이 필요

    • Set Up Project 클릭해서 진행

  • docker hub에 push 하기 위해 login이 필요하다. circleci 프로젝트 환경변수에 id,pw 등록해준다.
                                                                          circle ci 환경변수
  • docker pw는 Access Token으로 대체

                                                                           docker access token
  • repo .circleci 의 config.yml

    • working directory 알맞게 수정
    • mater branch일때 deploy 실행
version: 2
jobs:
 build:
  # Variable expansion in working_directory not supported at this time
  # You will need to modify the code below to reflect your github account/repo setup
  working_directory: /go/src/github.com/dotlike13/invoicer-chapter2
  docker:
   - image: circleci/golang:1.10
  steps:
   - checkout
   - setup_remote_docker

   - run: 
      name: Setup environment
      command: |
       gb="/src/github.com/${CIRCLE_PROJECT_USERNAME}";
       if [ ${CIRCLE_PROJECT_USERNAME} == 'Securing-DevOps' ]; then
         dr="securingdevops"
       else
         dr=$DOCKER_USER
       fi
       cat >> $BASH_ENV << EOF
       export GOPATH_HEAD="$(echo ${GOPATH}|cut -d ':' -f 1)"
       export GOPATH_BASE="$(echo ${GOPATH}|cut -d ':' -f 1)${gb}"
       export DOCKER_REPO="$dr"
       EOF
   - run: mkdir -p "${GOPATH_BASE}"
   - run: mkdir -p "${GOPATH_HEAD}/bin"
       
   - run:
      name: Testing application
      command: |
          go test \
          github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}

   - deploy:
       command: |
         if [ "${CIRCLE_BRANCH}" == "master" ]; then
           docker login -u ${DOCKER_USER} -p ${DOCKER_PASS};
           go install --ldflags '-extldflags "-static"' \
           github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME};
           mkdir bin;
           cp "$GOPATH_HEAD/bin/${CIRCLE_PROJECT_REPONAME}" bin/invoicer;
           docker build -t ${DOCKER_REPO}/${CIRCLE_PROJECT_REPONAME} .;
           docker images --no-trunc | awk '/^app/ {print $3}' | \
             sudo tee $CIRCLE_ARTIFACTS/docker-image-shasum256.txt;
           docker push ${DOCKER_REPO}/${CIRCLE_PROJECT_REPONAME};
         fi
  • master branch에서 파일 수정해서 ci 동작 시키기
  • circleci build 부분에서 docker hub에 올라간 이미지 확인

2. AWS 리소스 생성

  • 책에서는 aws-cli로 생성하지만 테라폼 연습겸할겸 작성해봄

  • vpc, ec2, db등 구성은 3tier 실습 참고

rds 생성

  • 위 3tier 구조에서 db subnet에 구성함
module "db" {
  source  = "terraform-aws-modules/rds/aws"

  identifier = "invoicer-db"

  engine               = "postgres"
  engine_version       = "14.3"
  family               = "postgres14" # DB parameter group
  major_engine_version = "14"         # DB option group
  instance_class       = "db.t4g.large"
  
  allocated_storage    = 5

  db_name  = "invoicer"
  username = "invoicer"
  password = "invoicerpassword"
  port     = "13306"

  multi_az               = false
  db_subnet_group_name   = module.vpc.database_subnet_group
  vpc_security_group_ids = [module.rds_security_group.security_group_id]

  maintenance_window              = "Mon:00:00-Mon:03:00"
  backup_window                   = "03:00-06:00"
  enabled_cloudwatch_logs_exports = ["postgresql", "upgrade"]
  create_cloudwatch_log_group     = true

  backup_retention_period = 1
  skip_final_snapshot     = true
  deletion_protection     = false

  performance_insights_enabled          = true
  performance_insights_retention_period = 7
  create_monitoring_role                = true
  monitoring_interval                   = 60
  monitoring_role_name                  = "example-monitoring-role-name"
  monitoring_role_use_name_prefix       = true
  monitoring_role_description           = "Description for monitoring role"

  parameters = [
    {
      name  = "autovacuum"
      value = 1
    },
    {
      name  = "client_encoding"
      value = "utf8"
    }
  ]

  db_option_group_tags = {
    "Sensitive" = "low"
  }
  db_parameter_group_tags = {
    "Sensitive" = "low"
  }

}

module "rds_security_group" {
  source  = "terraform-aws-modules/security-group/aws"
  version = "4.13.0"

  name        = "invoicer_db"
  description = "invoicer db security group"
  vpc_id      = module.vpc.vpc_id

  ingress_with_cidr_blocks = [
    {
      from_port   = 13306
      to_port     = 13306
      protocol    = "tcp"
      description = "invoicer db inbound"
      cidr_blocks = "0.0.0.0/0"
    },
    {
      cidr_blocks = "0.0.0.0/0"
      description = "ICMP"
      from_port   = -1
      protocol    = "icmp"
      to_port     = -1
    }
  ]
}

beanstalk 생성

  • application이 먼저 필요
  • solution stack은 data로 가장 최신 이미지 검색
  • application_version은 앞서 만든 도커 이미지를 불러오기 위한 리소스
    • 관련정보는 s3에 json형태로 저장함
    • application 먼저 생성된 이후 버전을 생성 할 수 있기때문에 depends_on 설정 필요
      • 안넣으면 apply할 때 리소스 생성 순서에 따라 에러 발생할 때 있음.
  • 이후 beanstalk_environment 설정
    • IamInstanceProfile가 꼭 필요함. 없으면 eb생성이 안됨
  • 필요한 iam 역할, 정책 생성
resource "aws_elastic_beanstalk_application" "invoicer" {
  name        = "invoicer"
  description = "Securing DevOps Inovicer application"

  appversion_lifecycle {
    service_role          = aws_iam_role.beanstalk_role.arn
    max_count             = 128
    delete_source_from_s3 = true
  }
}

data "aws_elastic_beanstalk_solution_stack" "docker" {
  most_recent = true
  name_regex  = "^64bit Amazon Linux .* running Docker$"
}

resource "aws_elastic_beanstalk_application_version" "invoicer" {
  name        = "invoicer-version"
  application = "invoicer"
  bucket      = aws_s3_bucket.this.id
  key         = aws_s3_object.this.id

  depends_on = [aws_elastic_beanstalk_application.invoicer]
}

resource "aws_elastic_beanstalk_environment" "eb" {
  name                = "invoicer-api"
  description         = "invoicer APP"
  application         = aws_elastic_beanstalk_application.invoicer.name
  solution_stack_name = data.aws_elastic_beanstalk_solution_stack.docker.name
  tier                = "WebServer"
  version_label       = "invoicer-version"

  setting {
    namespace = "aws:elasticbeanstalk:application:environment"
    name      = "INVOICER_POSTGRES_USER"
    value     = "invoicer"
  }
  setting {
    namespace = "aws:elasticbeanstalk:application:environment"
    name      = "INVOICER_POSTGRES_PASSWORD"
    value     = "invoicerpassword"
  }
  setting {
    namespace = "aws:elasticbeanstalk:application:environment"
    name      = "INVOICER_POSTGRES_DB"
    value     = "invoicer"
  }
  setting {
    namespace = "aws:elasticbeanstalk:application:environment"
    name      = "INVOICER_POSTGRES_HOST"
    value     = "invoicer-db.cqumm9p8ksgp.ap-northeast-2.rds.amazonaws.com"
  }
  setting {
    namespace = "aws:autoscaling:launchconfiguration"
    name = "IamInstanceProfile"
    value = "invoicer-eb-glen-profile"
  }
}

resource "aws_iam_instance_profile" "this" {
  name = "invoicer-eb-glen-profile"
  role = aws_iam_role.beanstalk_role.name
}

resource "aws_iam_role" "beanstalk_role" {
  name = "beanstalk_role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      },
    ]
  })

}

resource "aws_iam_role_policy_attachment" "beansservice" {
  role       = aws_iam_role.beanstalk_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSElasticBeanstalkService"
}

S3 생성

  • 앱버전을 관리하기 위해 json형식으로 작성한 파일을 s3에 업로드 한다.
    • 버킷생성
    • object 생성
    • bucket 접근을 위한 iam
resource "aws_s3_bucket" "this" {
  bucket = "glen-invoicer"
}

resource "aws_s3_object" "this" {
  depends_on = [aws_s3_bucket.this]
  bucket = "glen-invoicer"
  key    = "glen-invoicer/app-version.json"
  source = "app-version.json"
}

resource "aws_s3_bucket_policy" "this" {
  bucket = aws_s3_bucket.this.id
  policy = data.aws_iam_policy_document.this.json
}

resource "aws_iam_policy" "full" {
  name        = format("%s-s3-full-access-policy", aws_s3_bucket.this.id)
  path        = "/"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "s3:*",
        ]
        Effect = "Allow"
        Resource = [
          format("arn:aws:s3:::%s", aws_s3_bucket.this.id),
          format("arn:aws:s3:::%s/*", aws_s3_bucket.this.id),
        ]
      },
    ]
  })
}

배포 결과

  • beanstalk
  • app version

3. app run

  • version확인
  • post로 invoice 작성하고. get으로 확인
  • page
profile
어제보다 나은 엔지니어가 되기 위해서 공부중

0개의 댓글