AWS

Part 8. DevOps 개념 이해와 Immutable Infra

cwchoiit 2024. 1. 11. 22:03
728x90
반응형
SMALL
728x90
SMALL

 

AWS를 DevOps 개념과 엮어 사용하기 위해서 DevOps 개념에 대해 좀 자세히 이해해 보자.

 

DevOps란?

Develop + Operation의 합성어로 개발과 운영의 경계를 허물고 통합하고자 하는 문화 또는 철학을 의미한다. 기술이 아니다.

소프트웨어 개발 프로세스와 운영의 모든 단계의 통합과 자동화를 목표로 한다. 즉, 개발 - 빌드 - 테스트 - 배포 - 운영 - 모니터링의 이 영원히 반복되는 사이클을 통합하고 자동화하여 하나의 문화로 만드는 것을 목표로 삼는다고 보면 되겠다.

 

이 DevOps라는 개념이 도입되기 전엔 배포 방식은 개발과 운영의 철저한 분리 상태를 유지하고 개발자는 운영에 대해 생각하지 않고 운영자는 개발에 대해 생각하지 않는 그런 흐름이 진행됐다. 그러다 애자일(Agile)이 등장하고 기존 소프트웨어 개발 방식인 Waterfall 방식과 힘겨루기를 하다 마침내 DevOps라는 개념이 탄생했다.

 

애자일이란, 기존 Waterfall 방식과 달리(Waterfall 방식은 순차적으로 하나씩 진행하는 방식이다. 계획 - 요구사항 분석 및 정리 - 개발 - 테스트 - 빌드 - 배포... 이러한 일련의 과정을 물이 아래로 흘러내려가는 폭포수같이 단계가 있다고 해서 Waterfall이라는 이름을 채택한 것으로 널리 알려져 있다) 기간을 아주 짧게 설정하고 그 짧은 기간 동안 수행할 Task들을 하나씩 처리하여 기간 동안의 처리된 개발 변동 사항에 대해 작은 사이즈로 릴리스하는 방식을 말한다. 

 

이러다 DevOps에 하나가 더 추가되는데 이는 DevSecOps이다.

 

DevSecOps는 Security가 추가된 합성어로 보안까지 포함하도록 확장된 개념이다. 소프트웨어 배포에 관여하는 모든 사람들이 보안을 최우선으로 하는 문화.

 

DevOps 핵심

DevOps 업무의 주 대상은 개발자이다. 그래서 개발자가 운영에 참여할 수 있는 환경과 문화를 제공하고 개발자가 비즈니스 로직에 집중할 수 있도록 지원하는 것이 DevOps의 핵심이라고 본다. 개발과 운영 사이에 놓인 커다란 벽을 허무는 것.

 

DevOps 업무 도메인

도메인 내용
네트워크 - 가상 네트워크 및 물리 네트워크 구성
- 프록시 / VPN 서버 운영
- DNS 서버 운영
클라우드 플랫폼 - 개발자들이 활용할 수 있도록 클라우드 환경 운영 (자체 클라우드, 퍼블릭 클라우드)
배포 플랫폼 - Gitlab/Github 등 개발 협업 플랫폼 운영
- CI/CD 파이프라인 시스템 구축 및 운영
- QA 테스트 및 성능 테스트를 위한 환경 제공
- 패키지 저장소 운영 및 배포 산출물 관리
보안 플랫폼 - LDAP, AD, SAML 등을 활용하여 통합된 임직원 계정계 운영
- 서버 및 데이터베이스 접근제어 시스템 구축 및 운영
오케스트레이션 플랫폼 - K8s, ECS, Nomad와 같은 오케스트레이션 시스템 구축 및 운영
- Airflow, Argo Workflows와 같은 워크플로우 엔진 구축 및 운영
데이터 플랫폼 - MySQL, DynamoDB, Redis와 같은 데이터베이스 구축 및 운영
- RabbitMQ, Kafka, SQS와 같은 메시징 서비스 구축 및 운영
- 데이터 웨어하우스, BI 대시보드 구축 및 운영
관측 플랫폼 - 로그, 메트릭, 업타임, APM 정보를 관측할 수 있는 중앙화 된 시스템 구축 및 운영
- 주요 이벤트에 대한 알림 시스템 구축
서비스 운영 - 개발자들과 협업하여 서비스 공동 운영

 

DevOps 팀 핵심 지표

지표 내용
장애 복구 시간 (MTTR: Mean Time To Recovery) 얼마나 빠르게 장애 상황에서 복구할 수 있는가?
변경으로 인한 결함률 (Change Failure Rate) 변경 사항으로 인한 장애가 얼마나 발생하는가?
배포 빈도 (Deployment Frequency) 얼마나 배포를 자주 하는가?
변경 반영 소요 시간 (Lead Time for Changes) 변경 사항을 프로덕션 배포에 걸리는 소요 시간은 얼마인가?

 

 

 

Mutable Infra / Immutable Infra 

가변 인프라(Mutable Infra) 불변 인프라(Immutable Infra)에 대해 알아보자.

 

가변 인프라(Mutable Infra)

어떤 웹 서버 구축을 예로 들어보자. 웹 서버를 구축하기 위해 물리 서버를 한 대 구입하고 그 안에 웹 서버가 실행가능한 상태를 만들어 웹 서버를 실행한다. 그러다 시간이 흘러 버전 업그레이드 또는 기술의 변경 같은 변경사항이 있을 때 서버는 업데이트 및 수정이 일어난다. 즉, 서버가 이전 환경과 달리 변경된 환경이다. 최초 배포 상태와 다른 상태, 환경으로 배포가 된다. 

 

이렇게 인프라가 변하는 환경을 가변 인프라라고 한다. 

불변 인프라(Immutable Infra)

위 예시 그대로 웹 서버 구축을 한다고 했을 때 웹 서버를 구축하기 위해 필요한 모든 환경을 구성한 뒤 웹 서버를 실행한다. 그러다 시간이 흘러 버전의 변경 또는 기술의 변경점이 생길 때 기존에 구축된 서버에 변경 사항이 가해지는 게 아니라 아예 새로운 서버를 만들어 기존 서버를 대체한다. 즉, 최초 서버가 배포된 이후 절대 변경되지 않는 형태의 인프라를 불변 인프라라고 한다.

 

가변 인프라에서 불변 인프라 추세로

가상화 및 클라우드 컴퓨팅이 널리 사용되기 이전 환경은 물리 서버를 중심으로 구성되었다. 물리 서버는 비용도 많이 발생하고 이 물리 서버 위에 서버를 실행하기까지 시간도 많이 소요되는데 이러한 점이 가변 인프라의 시작점이다. 즉, 새로운 서버를 또 구입하는 비용과 구입한 후 설정을 처음부터 다시 하기 부담스러우니 기존 서버를 가지고 변경지점이 생기면 점차 변경해 나가는 것이 더 효율적인 인프라 구축 방식이었다. 

 

그러나, 이 방식은 어떤 문제를 발생시키냐? 점점 변경이 가해지면 가해질수록 최초 서버의 환경에서 설정의 변화가 많이 생겨난다. 이러한 것을 '스노우 플레이크'라고 표현한다. 그리고 서비스의 다운 타임이 최소화되도록 하니 서버의 문서화보다 변경 - 적용 - 배포가 먼저가 되고 그 결과 문서화가 잘 이루어지지 않고 그러다 보니 최초 배포 환경과 점점 다른 설정 환경으로 변하는 지점 파악이 어려워진다. 이러한 것을 '컨피그레이션 드리프트'라고 한다. 이에 더해서 시스템의 변경은 리스크가 따른다. 변경이 원활히 수행된다면 더할 나위 없이 좋겠지만 어디 그랬던 적이 있는가? 항상 문제는 발생하기 마련이기 때문에 변경하다가 문제가 생기면 이 지점에서 또 병목 현상이 생길 수 있다. 그리고 또 하나의 문제는 이렇게 계속 변경사항이 생기면 생길수록 프로덕션 환경과 동일한 스테이지 환경을 만들기도 어려워진다는 것이다. 그 결과 디버깅 및 테스트하기도 어려워진다는 것.

 

이러한 단점을 가상화/클라우드 컴퓨팅 기술이 활성화되면서 극복하게 됐다. 클라우드 서비스는 비용이 저렴하고 (사용한 만큼만 지불하면 된다. 이 말은 물리서버를 구비하는 물릴 수 없는 자본지출을 운영지출로 대체할 수 있다는 것이고 그 결과 비용의 효율적인 사용이 가능해진다.) 확장이 수월하고 생성 및 폐기까지 몇 초에서 몇 분밖에 걸리지 않는다.  

 

불변 인프라의 모든 배포는 검증되고 버전 관리가 된 이미지를 바탕으로 새 서버를 프로비저닝 하여 실행된다. 그 결과 이러한 배포는 서버의 이전 상태에 의존하지 않게 된다. 불변 인프라의 모든 설정 변경은 문서화와 함께 버전 컨트롤에 변경된 이미지를 저장하고 그 이미지를 교체 서버에 배포하는 자동화되고 통일된 배포 프로세스(클라우드 API나 프로그래밍 친화적으로 자동으로 새 서버에 프로비저닝)를 사용하면서 구현된다. 배포된 후 변경 지점이 전혀 없으니 Configuration Drift가 발생하지 않게 된다.

 

 

Terraform

불변 인프라를 프로그래밍 친화적으로 새 서버를 프로비저닝 하는 기술 중 하나인 Terraform을 사용해서 AWS에 인스턴스를 새로 프로비저닝해보자. 'Terraform'은 클라우드에 프로비저닝, 리소스 관리를 자동으로 할 수 있게 해주는 인프라스트럭쳐 자동화 도구이다.

 

여기선 약간의 가정이 필요한데, 기존 배포된 서버가 있고 새 배포를 하는 것이라고 가정하자. 그렇다는 것은 기존 배포된 서버에서 사용하는 데이터가 있었을 것이고 그 데이터는 AWS S3, DynamoDB에서 관리하고 있었다고 가정해 보자. 그렇기에 S3, DynamoDB를 만드는 작업부터 해보자.

 

AWS DynamoDB 생성

S3 버킷을 만드는 작업은 이전 포스팅에서 해봤으니 생략하고 DynamoDB를 만들어보자.

검색창에 'DynamoDB'를 검색하면 서비스가 나온다. 클릭해 보자.

 

우측 상단 'Create table' 버튼을 클릭하자.

 

상단부터 Table name, Partition key를 입력하자.

 

그 외 설정은 기본 설정으로 한 뒤 생성하면 된다.

 

 

Terraform install

이제 Terraform CLI를 이용해야 하니까 먼저 설치를 해야 한다. 아래 링크에 설치 가이드가 있다.

 

Install | Terraform | HashiCorp Developer

Explore Terraform product documentation, tutorials, and examples.

developer.hashicorp.com

 

본인은 macOS를 사용하므로 다음 명령어로 설치할 것.

brew update
brew tap hashicorp/tap
brew install hashicorp/tap/terraform

 

잘 설치가 됐는지 확인하기 위해 다음 명령어를 입력한다.

terraform -help

 

Usage 관련 내용이 나오면 성공.

 

 

Terraform 소스코드

소스에 대한 깊은 내용은 매뉴얼을 참고하자. 지금 여기서 핵심은 코드로 프로비저닝을 할 수 있는 도구를 사용해 보는 것에 의의를 두는 것.

 

backend.tf

terraform {
  backend "s3" {
    bucket         = "terraform-s3-cwchoi"
    dynamodb_table = "terraform-db-cwchoi"
    encrypt        = true
    key            = "remote"
    region         = "ap-northeast-2"
  }
}

 여기서는 S3, DynamoDB를 설정하는 파일이다. bucket, dynamodb_table에 방금 생성한 버킷과 DB명을 적었다. 

 

data.tf

data "aws_ami" "amazon_linux2" {
  most_recent = true

  owners = ["amazon"]

  filter {
    name = "name"

    values = [
      "amzn-ami-hvm-*-x86_64-gp2",
    ]
  }

  filter {
    name = "owner-alias"

    values = [
      "amazon",
    ]
  }
}

 

main.tf

locals {
  common_tags = {
    Environment = "dev"
    Application = "myapp"
    Terraform   = "true"
  }
}

resource "aws_instance" "ec2_example" {
  ami           = data.aws_ami.amazon_linux2.id
  instance_type = "t2.micro"
  tags = {
    Name = "cwchoi-tf-ec2-example"
  }
  subnet_id = "subnet-00a3643ae0bf65523"
}

 

provider.tf

provider "aws" {

  region  = "ap-northeast-2"

  access_key = "XX"
  secret_key = "XX"

  default_tags {
    tags = local.common_tags
  }
}

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
}

provider는 AWS이고 IAM 유저의 access_key와 secret_key를 입력해 주자.

 

variables.tf

variable "region" {
  default = "ap-northeast-2"
}

 

이 파일들이 위치한 경로에서 다음 명령어를 입력한다.

terraform init

입력하고 나면 해당 경로에 .terraform.lock.hcl 파일이 자동으로 생성되는 것을 확인하면 된다.

 

plan 명령어로 어떤 리소스가 생성될지 확인할 수 있다.

terraform plan -lock=false

 

output:

data.aws_ami.amazon_linux2: Reading...
data.aws_ami.amazon_linux2: Read complete after 1s [id=ami-0007d44f4d00c13b1]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.ec2_example will be created
  + resource "aws_instance" "ec2_example" {
      + ami                                  = "ami-0007d44f4d00c13b1"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (known after apply)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "cwchoi-tf-ec2-example"
        }
      + tags_all                             = {
          + "Application" = "myapp"
          + "Environment" = "dev"
          + "Name"        = "cwchoi-tf-ec2-example"
          + "Terraform"   = "true"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

 

EC2 인스턴스가 생성된다는 결론이 나온다. 왜냐하면 main.tf 파일에서 resource에 aws_instance를 생성하게 설정했기 때문이다.

 

이제 새 프로비저닝을 하면 된다. 다음 명령어를 수행하자.

terraform apply -lock=false

 

다음 확인 메시지가 나오는데 'yes'를 입력하면 된다.

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value:

 

생성이 완료되면 다음과 같은 결과가 나온다.

aws_instance.ec2_example: Creating...
aws_instance.ec2_example: Still creating... [10s elapsed]
aws_instance.ec2_example: Still creating... [20s elapsed]
aws_instance.ec2_example: Still creating... [30s elapsed]
aws_instance.ec2_example: Creation complete after 33s [id=i-01e423c5447a7a27f]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

 

살제로 생성이 됐는지 확인해 보려면 AWS Console로 가보자.

잘 생성된 것을 볼 수 있다.

 

이렇게 생성된 리소스를 이제 삭제해 보자.

terraform destroy -lock=false

 

아래처럼 물어보는데 'yes'를 입력하면 된다. 당연히 여기서 삭제하는 건 init을 했을 때의 관리되고 있는 리소스들을 삭제하는 것.

...


Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value:


output:

aws_instance.ec2_example: Destroying... [id=i-01e423c5447a7a27f]
aws_instance.ec2_example: Still destroying... [id=i-01e423c5447a7a27f, 11s elapsed]
aws_instance.ec2_example: Still destroying... [id=i-01e423c5447a7a27f, 21s elapsed]
aws_instance.ec2_example: Still destroying... [id=i-01e423c5447a7a27f, 31s elapsed]
aws_instance.ec2_example: Still destroying... [id=i-01e423c5447a7a27f, 41s elapsed]
aws_instance.ec2_example: Destruction complete after 41s

Destroy complete! Resources: 1 destroyed.

 

실제로 삭제가 됐는지 확인하기 위해 또 AWS Console에서 확인해 보자.

 

정상적으로 'Terminated' 됐다.

 

 

 

결론

이런 식으로 코드친화적으로 불변 인프라 방식의 프로비저닝을 할 때 'Terraform'을 이용할 수 있다.

변경될 부분에 대해서 기존 인스턴스에서 수정하는 방식이 아니라 아예 'Destroy' 후 변경사항을 적용 후 새로운 버전으로 프로비저닝을 하는 것.

 

728x90
반응형
LIST

'AWS' 카테고리의 다른 글

Part 13. Auto Scaling  (0) 2024.01.18
Part 11. VPC로 네트워크 설계하기  (0) 2024.01.14
Part 7. S3 버킷 생성하기  (0) 2024.01.11
Part 6. EC2 서비스 생성 및 Nginx 실행해보기  (0) 2024.01.11
Part 5. AWS IAM  (0) 2024.01.11