728x90
반응형

테라폼 backend용 s3 버킷 생성

provider "aws" {
    region = "ap-northeast-2"
}

resource "aws_s3_bucket" "example" {
  bucket = "iac-serverce1"

  tags = {
    Name        = "iac-service1"
    Environment = "Dev"
    Management  = "Terraform"
    CreatedBy   = "hwan001"
  }
}

 

728x90
반응형
728x90
반응형

Dockerfile?

  • Dockerfile은 원하는 Docker Container Image를 생성하기 위한 스크립트 파일이다.
  • Docker는 build 옵션을 통해 Dockerfile에 나열된 명령문을 차례대로 수행하며 Container Image를 생성해준다.
  • Dockerfile을 읽을 줄 안다는 것은 해당 이미지가 어떻게 구성되어 있는지 알 수 있다는 의미이다.

 

Dockerfile 작성 방법

키워드

FROM: 시작점이 될 베이스 이미지를 지정한다.

 

MAINTAINER: 이미지를 생성한 개발자의 정보를 표시한다. (1.13.0 이후에는 권장되지 않고, LABEL을 사용하는 것이 좋다.)

 

LABEL: 이미지에 메타데이터를 추가한다. key-value 형태로 지정된다.

 

RUN:
이미지 내에서 명령어를 실행한다. 실행 결과는 새로운 레이어에 기록되고, 이 레이어는 최종 이미지에 포함된다.
각 RUN 명령은 새로운 레이어를 생성하며, 이러한 레이어들은 캐시되어 재사용될 수 있다.

 

WORKDIR:
컨테이너 내에서의 작업 디렉토리를 지정한다.
해당 디렉토리가 없으면 자동으로 생성되며, 이후의 작업들은 이 디렉토리 내에서 실행된다.

 

EXPOSE:
이미지를 실행할 때 열려야 하는 포트를 지정한다.
이 포트는 컨테이너 실행 시 -p 옵션으로 호스트와 매핑될 수 있다.

 

USER: 컨테이너가 실행될 때 사용될 사용자를 지정한다. (기본값 root)

 

COPY / ADD:
호스트 시스템의 파일이나 디렉토리를 이미지에 복사한다.
ADD는 COPY보다 확장된 기능을 제공한다. ADD는 URL로부터 파일을 가져오거나 압축 해제 기능도 제공한다.
특별한 기능이 필요하지 않은 경우, COPY를 사용하는 것이 권장된다.

 

ENV: 컨테이너 내에서 사용될 환경 변수를 설정한다.

 

CMD / ENTRYPOINT:
컨테이너를 생성하거나 실행할 때 수행될 명령어를 정의한다.
docker run 명령으로 새 컨테이너를 생성하거나, docker start 명령으로 정지된 컨테이너를 시작할 때 해당 명령어가 실행된다.
주로 컨테이너 내부에서 지속적으로 실행되어야 하는 서버나 애플리케이션을 시작할 때 사용된다.

 

CMD:
CMD는 docker run 실행 시 추가적인 명령어가 주어지면, 해당 명령어를 ENTRYPOINT에 지정된 명령어의 인자로 사용한다. 만약 ENTRYPOINT가 정의되어 있지 않다면, CMD에서 지정한 명령어를 실행한다.

Dockerfile 내에서 CMD를 여러 번 정의할 수 있지만, 마지막으로 정의된 CMD만 최종적으로 사용된다.

 

CMD는 3가지 형태로 작성될 수 있다:
- CMD ["executable", "param1", "param2"]: 실행할 프로그램과 그에 대한 인자를 지정한다.
- CMD ["param1", "param2"]: ENTRYPOINT로 지정된 실행 가능한 파일의 인자로 사용된다.
- CMD command param1 param2: shell 형태로 명령어를 실행한다. 여기서는 /bin/sh -c를 사용하여 해당 명령어를 실행한다.

 

ENTRYPOINT :
ENTRYPOINT는 docker run 실행 시, 추가적인 명령어가 주어지면 이 명령어는 ENTRYPOINT에 지정된 명령어에 대한 인자로 사용된다. CMD에서 기본 인자가 제공되었을 때 docker run에서 명령어를 추가로 주게 되면, CMD의 인자는 덮어쓰여진다.

ENTRYPOINT 명령은 2가지 형태로 제공된다:
- exec 형태: ENTRYPOINT ["executable", "param1", "param2"]. 이 형태는 명령어가 PID 1로 실행되어 신호 처리가 올바르게 이루어진다.
- shell 형태: ENTRYPOINT command param1 param2. 이 형태를 사용할 때, 명령어는 실제로 /bin/sh -c 내에서 실행되므로 신호 처리에 주의가 필요하다.

 

ENTRYPOINT는 CMD와 함께 사용될 때, ENTRYPOINT는 실행할 명령어를, CMD는 그 명령어의 기본 인자로 사용된다.

 

 

Docker 빌드

  • Dockerfile의 기본이름은 Dockerfile이다.
    파일명을 이렇게 설정하면 파일이 위치한 경로에서 docker build . 만 해도 빌드가 가능하다.
    하지만 이렇게 생성하면  이미지의 이름과 태그가 없기 때문에 -t 옵션으로 태그와 파일명 지정이 가능하다.
docker build . -t container_name:tag
  • Dockerfile은 파일명 변경이 가능하다.
    위에서 파일명을 다르게 지정했다면  -f 옵션으로 지정이 가능하다.
docker build -t container_name:tag -f my.Dockerfile .

 

728x90
반응형
728x90
반응형

네임스페이스 확인

kubectl get namespace

 

네임스페이스 변경하기

kubectl config set-context --current --namespace={NAMESPCE}

 

 

728x90
반응형
728x90
반응형

Git과 PR(Pull Request)을 활용한 협업

 인프라의 규모가 확장되면서 여러 팀원들과 함께 작업하는 상황에서는 동일한 상태 파일을 공유하고 동기화하는 것이 중요해졌다.

 

https://kschoi728.tistory.com/139

 

유형 1은 직접 .tf 파일과 tfstate 파일을 공유하는 방식이다. 이런 방식으로 파일을 공유할 수는 있지만, 수동으로 관리하는 데에는 여러 번거로운 작업들이 포함된다. 이 과정에서 인간의 실수나 정보의 누락이 발생할 수 있기 때문에 이러한 문제점을 해결하고자 버전 관리 시스템(VCS)의 도입이 필요해졌다.

유형 2에서는 VCS(예: git, svn)를 사용하여 해당 파일들을 효율적으로 관리한다. 이를 통해 변경 이력을 체계적으로 추적할 수 있으며, 필요한 경우 이전 버전으로 쉽게 롤백할 수 있게 되었다.

유형 3은 git을 사용하여 .tf 파일을 관리하는 동시에, s3와 같은 백엔드 서비스를 활용하여 tfstate 파일을 안전하게 저장하고 관리하는 방식이다. 이 구조를 사용하면 각 파일의 특성에 맞는 최적화된 관리 방식을 선택할 수 있다.

 

 일반적으로는 유형 3의 구조에서 Git 저장소에 브랜치를 생성한 후 PR을 보내서 작업을 진행하게 된다.

PR은 git으로 코드를 관리할 때 주로 사용되는 브랜치 branch를 이용하는 방법으로 작업자가 코드 수정을 위해 새로운 브랜치를 생성하고 작업한 후 본인의 브랜치를 push하여 코드리뷰 후 Merge를 요청하는 방식이다.

Push와 Pull만으로도 코드 협업이 가능하긴 하지만 이렇게 할 경우, 다른 사람이 작성한 커밋을 확인하기가 쉽지 않고 리모트 저장소에 푸시할 때가 되어야 충돌 상황을 확인 할 수 있다.
PR을 사용하면 작업된 테라폼 코드에 대한 자연스러운 리뷰와 메인스트림 main branch의 병합을 관리하기 수월해진다.

 

이전에 만들었던 Terraform VPC Module에 PR을 보내기 위해 feature 브랜치를 생성했다.

브랜치 생성

작업 후에 PR을 생성하고 main 브랜치에 Merge 해보자.

commit 후 push
open a pull request
comment
merge

 

위 과정을 거치면 다른 브랜치를 통해서 작업한 내용을 main브랜치에 합칠 수 있다.

 


Hashcorp TFC (Terraform Cloud) 백엔드

  위에서 VCS와 PR을 활용하는 방법을 확인했다. 하지만 유형3에서 코드의 관리만큼 중요한 상태 파일의 관리를 해결하지 못했는데,

s3 등의 시스템들을 활용하면 백엔드로 관리하면 상태 파일을 안정적으로 공유할 수 있다. 

그 중 TFC 백엔드에 대해서 정리해보려고 한다.

 

하시코프에서 프로비저닝 대상과 별개로 State를 관리할 수 있도록 SaaS 환경인 TFC를 무상 제공한다.

TFC는 아래 링크로 접속할 수있다. 

https://app.terraform.io/session

 

Terraform Cloud by HashiCorp

 

app.terraform.io

 

먼저, email로 계정을 생성한 뒤 로그인하여 Organizations를 생성한다.

최초 화면

 

hwan001-test-org라는 이름으로 Organizations를 생성했다.

org 생성

 

이제 아래의 코드로 테라폼 파일을 만들어주자.

terraform{
  cloud{
    organization = "hwan001-test-org"      # 생성한 ORG 이름 지정
    hostname     = "app.terraform.io"      # default

    workspaces {
      name = "terraform-aws-collaboration"  # 없으면 생성됨
    }
  }
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 4.0"
    }
  }
}

provider "aws" {
  region  = "ap-northeast-2"
  # shared_config_files      = ["~/.aws/config"]
  # shared_credentials_files = ["~/.aws/credentials"]
}

module "vpc" {
  source = "git::https://github.com/aws-hwan-001/vpc.git"

  cidr_block             = "10.10.0.0/16"
  tags                   = { Name = "hwan001-vpc" }
  public_subnet_cidr    = "10.10.1.0/24"
  public_subnet_tags    = { Name = "hwan001-public-subnet" }
  private_subnet_cidr    = "10.10.2.0/24"
  private_subnet_tags    = { Name = "hwan001-private-subnet" }
}

 

terraform init을 실행하면 login이 필요하다는 경고가 나온다.

terraform login 명령어를 실행하고 yes를 입력하면 아래처럼 토큰을 생성하는 페이지가 생성(웹에 로그인되어 있을 경우)된다.

토큰생성 페이지

해당 페이지에서 토큰을 생성한 후 복사하고, shell에 입력해주면 아래와 같은 화면이 나오면서 login 된다.

terraform login

 

로그인 후 다시 terraform init을 진행하면 정상적으로 진행되면서 웹UI에서 새로운 프로젝트가 생긴걸 볼 수 있다.

 

배포를 원하는 AWS 계정의 Credential  정보를 아래 경로에 Variable Sets으로 설정해주자.

Settings > Variable Sets

 

이 상태에서 Terraform plan과 apply가 아래처럼 성공하면 아래처럼 state를 TFC에서 확인할 수 있다.

728x90
반응형
728x90
반응형

젠킨스에 설치된 Plugin 목록 얻기

 아래 명령어로 젠킨스에 설치된 플러그인의 목록을 얻을 수 있다.

USERNAME과 PASSWORD은 젠킨스에 로그인이 가능한 계정 정보, SERVER IP와 PORT는 조회를 원하는 젠킨스 서버의 정보이다.

 위 내용에 특수기호가 들어가는 경우는 \를 붙여 사용한다. (PASSWORD가 passwd! 일 경우, passwd\!) 
SERVER IP에는 https등을 제외하고 아이피만 넣어주어야 한다.

JENKINS_HOST="USERNAME:PASSWORD@SERVER_IP:PORT";
curl -sSL "http://$JENKINS_HOST/pluginManager/api/xml?depth=1&xpath=/*/*/shortName|/*/*/version&wrapper=plugins" | perl -pe 's/.*?<shortName>([\w-]+).*?<version>([^<]+)()(<\/\w+>)+/\1 \2\n/g'|sed 's/ /:/'

# ex)
# JENKINS_HOST="admin:1234@0.0.0.0:8080";
# curl -sSL "http://$JENKINS_HOST/pluginManager/api/xml?depth=1&xpath=/*/*/shortName|/*/*/version&wrapper=plugins" | perl -pe 's/.*?<shortName>([\w-]+).*?<version>([^<]+)()(<\/\w+>)+/\1 \2\n/g'|sed 's/ /:/'

결과

728x90
반응형

'DevOps > CICD' 카테고리의 다른 글

[DevOps] Jenkins로 Flask 웹 서버 컨테이너 CI/CD 구현하기  (0) 2022.10.10
728x90
반응형

State  file

 상태 파일은 terraform apply시에 생성되는 .tfstate 파일이다.

해당 파일은 인프라의 상태를 json 형태로 가지고 있는데, 테라폼 내부에서만 사용하기 위한 파일이기 때문에 테라폼 상태 파일을 직접 편집하거나 직접 읽는 코드로 작성해서는 안된다.

 

팀 단위로 작업하는 경우 아래 조건이 갖춰져야 한다.

  1. 상태 파일을 저장하는 공유 스토리지 (Shared storage for state files)
    • 각 팀원이 동일한 테라폼 상태 파일 사용을 위해서, 공유 위치에 저장이 필요
  2. 상태 파일 잠금 (Locking state files)
    • 잠금 기능 없이 동시에 테라폼 실행 시 여러 테라폼 프로세스가 상태 파일을 동시에 업데이트하여 경쟁 상태(race condition)로 인한 충돌 가능
  3. 상태 파일 격리 (Isolating state files)
    • 테스트(dev), 검증(stage), 상용(prodction) 등 각 환경에 대한 상태 파일의 격리가 필요

 

AWS S3, Azure Blob Storage, Google Cloud Storage 등이 원격 백엔드를 지원하기 때문에 많이 쓰인다.

이런 백엔드를 사용할 경우 일반적으로 발생하는 아래 문제들을 해결할 수 있다.

  1. 수동 오류: plan/apply 실행 시 마다 해당 백엔드에서 파일을 자동을 로드, apply 후 상태 파일을 백엔드에 자동 저장
  2. 잠금: apply 실행 시 테라폼은 자동으로 잠금을 활성화, -lock-timout=<TIME> 로 대기 시간 설정 지정 가능
  3. 보안: 대부분 원격 백엔드는 기본적으로 데이터를 보내거나 상태 파일을 저장할 때 암호화 기능을 지원

 

아래 코드를 사용하면 DynamoDB로 잠금 상태를 제어하는 AWS S3 Backend를 만들수 있다.

provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_s3_bucket" "mys3bucket" {
  bucket = "hwan001-t101study-tfstate"
}

resource "aws_s3_bucket_versioning" "mys3bucket_versioning" {
  bucket = aws_s3_bucket.mys3bucket.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_dynamodb_table" "mydynamodbtable" {
  name         = "terraform-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

S3 bucket 생성
DynamoDB 생성

 

만들어진 백엔드와 DynamoDB 잠금은 아래처럼 사용할 수 있다.

provider "aws" {
  region  = "ap-northeast-2"
}

terraform {
  backend "s3" {
    bucket = "hwan001-t101study-tfstate"
    key    = "dev/terraform.tfstate"
    region = "ap-northeast-2"
    dynamodb_table = "terraform-locks"
    # encrypt        = true
  }
}

Module

 모듈은 대부분의 프로그래밍 언어에서 쓰이는 라이브러리나 패키지와 역할이 비슷하다.

모듈은 기본적으로 아래와 같은 구조를 가지며 이렇게 모듈화를 할 경우 재활용성이 높아진다.

 

Root-Module과 Child-Module로 나누어지고, root 모듈 내부에서  child 모듈을 불러서 사용할 수 있다.

모듈을 사용하는 방법은 로컬 디렉토리, 테라폼 레지스트리와 github에 있는 모듈 사용 등이 있다.

 

아래는 깃허브를 사용한 방식으로 ec2 인스턴스를 띄워봤다.

먼저 github에 public 리포지토리를 생성한다. 생성 시 .gitignore에서 Terraform을 선택하면 .terraform 등의 과정에서 생성된 파일들이 github push 시에 올라가지 않는다.

 

VPC Module

 

GitHub - aws-hwan-001/vpc

Contribute to aws-hwan-001/vpc development by creating an account on GitHub.

github.com

data "aws_availability_zones" "available" {
  state = "available"
}
# variables.tf
variable "cidr_block" {
  description = "The CIDR block for the VPC"
  type        = string
}

variable "tags" {
  description = "Tags for the VPC"
  type        = map(string)
  default     = {}
}

variable "primary_subnet_cidr" {
  description = "CIDR block for the primary subnet"
  type        = string
}

variable "primary_subnet_tags" {
  description = "Tags for the primary subnet"
  type        = map(string)
  default     = {}
}

variable "secondary_subnet_cidr" {
  description = "CIDR block for the secondary subnet"
  type        = string
}

variable "secondary_subnet_tags" {
  description = "Tags for the secondary subnet"
  type        = map(string)
  default     = {}
}


# main.tf
resource "aws_vpc" "this" {
  cidr_block = var.cidr_block
  tags       = var.tags
}

resource "aws_subnet" "primary" {
  vpc_id            = aws_vpc.this.id
  cidr_block        = var.primary_subnet_cidr
  availability_zone = data.aws_availability_zones.available.names[0]
  tags              = var.primary_subnet_tags
}

resource "aws_subnet" "secondary" {
  vpc_id            = aws_vpc.this.id
  cidr_block        = var.secondary_subnet_cidr
  availability_zone = data.aws_availability_zones.available.names[1]
  tags              = var.secondary_subnet_tags
}

# output.tf
output "vpc_id" {
  description = "The ID of the VPC"
  value       = aws_vpc.this.id
}

output "primary_subnet_id" {
  description = "The ID of the primary subnet"
  value       = aws_subnet.primary.id
}

output "secondary_subnet_id" {
  description = "The ID of the secondary subnet"
  value       = aws_subnet.secondary.id
}

 

Security Group Module

 

GitHub - aws-hwan-001/sg

Contribute to aws-hwan-001/sg development by creating an account on GitHub.

github.com

# variables.tf
variable "description" {
  description = "Description of the security group"
  type        = string
}

variable "vpc_id" {
  description = "VPC ID to associate the security group with"
  type        = string
}

variable "ingress_rules" {
  description = "List of ingress rules"
  type        = list(object({
    from_port   = number
    to_port     = number
    protocol    = string
    cidr_blocks = list(string)
  }))
}

variable "name" {
  description = "Name of the security group"
  type        = string
}

# main.tf
resource "aws_security_group" "this" {
  description = var.description
  vpc_id      = var.vpc_id

  dynamic "ingress" {
    for_each = var.ingress_rules
    content {
      from_port   = ingress.value.from_port
      to_port     = ingress.value.to_port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = var.name
  }
}

# output.tf
output "security_group_id" {
  description = "The ID of the security group"
  value       = aws_security_group.this.id
}

 

 

EC2 Module

 

GitHub - aws-hwan-001/ec2

Contribute to aws-hwan-001/ec2 development by creating an account on GitHub.

github.com

# variables.tf
variable "instance_type" {
  description = "EC2 instance type"
  type        = string
}

variable "subnet_id" {
  description = "Subnet id to launch the instance in"
  type        = string
}

variable "security_group_ids" {
  description = "List of security group ids to associate with the instance"
  type        = list(string)
}

variable "instance_name" {
  description = "Name to be used on all resources as prefix"
  type        = string
}

variable "associate_public_ip_address" {
  description = "Associate a public ip address with the instance"
  type        = bool
  default     = false
}

# main.tf
data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"]  # Canonical
}

resource "aws_instance" "this" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = var.instance_type
  subnet_id     = var.subnet_id
  vpc_security_group_ids = var.security_group_ids
  associate_public_ip_address = var.associate_public_ip_address

  tags = {
    Name = var.instance_name
  }
}

# output.tf
output "instance_id" {
  description = "The ID of the instance"
  value       = aws_instance.this.id
}

 

이제 만들어진 모듈을 사용해 리소스를 생성해보자.

ec2 모듈에 count = 3을 넣어주어 3개의 인스턴스를 생성했다.

provider "aws" {
  region  = "ap-northeast-2"
}

terraform {
  backend "s3" {
    bucket = "hwan001-t101study-tfstate"
    key    = "dev/terraform.tfstate"
    region = "ap-northeast-2"
    dynamodb_table = "terraform-locks"
    # encrypt        = true
  }
}


module "vpc" {
  source = "git::https://github.com/aws-hwan-001/vpc.git"

  cidr_block             = "10.10.0.0/16"
  tags                   = { Name = "hwan001-vpc" }
  primary_subnet_cidr    = "10.10.1.0/24"
  primary_subnet_tags    = { Name = "hwan001-subnet-1" }
  secondary_subnet_cidr  = "10.10.2.0/24"
  secondary_subnet_tags  = { Name = "hwan001-subnet-2" }
}


module "security_group" {
  source  = "git::https://github.com/aws-hwan-001/sg.git"
  
  description = "hwan001 Security Group"
  vpc_id      = module.vpc.vpc_id
  name        = "hwan001-sg"
  ingress_rules = [
    {
      from_port   = 22
      to_port     = 22
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      from_port   = 80
      to_port     = 80
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      from_port   = 443
      to_port     = 443
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      from_port   = 8080
      to_port     = 8080
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    }
  ]
}


module "ec2_instance" {
  source  = "git::https://github.com/aws-hwan-001/ec2.git"
  count = 3
  
  instance_type = "t2.micro"
  subnet_id     = module.vpc.primary_subnet_id
  security_group_ids = [module.security_group.security_group_id]
  instance_name = "hwan001-ec2"
  associate_public_ip_address = true
}

 

상태파일은 위에서 만든 백엔드를 사용하고 있는 걸 볼 수 있다.

 


 

728x90
반응형
728x90
반응형

조건문

 Terraform에는 다른 언어처럼 조건문을 위한 if 키워드가 없기 때문에 3항 연산자를 사용하여 조건문을 작성해야 한다.

예를들면 아래처럼 환경에 대한 정보를 변수로 입력받아 product 환경일 경우 5번, 아닐 경우 1번만 리소스를 생성하도록 할 수 있다.

resource "aws_instance" "hwan001_instance" {
  count = var.env == "prod" ? 5 : 1
}

 

만약 dev 환경일 경우에만 리소스를 생성하고 싶다면 아래처럼 작성할 수 있다.

provider "aws" {
  region = "ap-northeast-2" 
}

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"]  # Canonical
}

resource "aws_instance" "hwan001-ec2-dev" {
  count				= var.env == "dev" ? 1 : 0
  ami				= data.aws_ami.ubuntu.id
  instance_type			= "t2.micro"
  subnet_id			= aws_subnet.primary_az.id
  vpc_security_group_ids	= [aws_security_group.hwan001-sg.id]
  associate_public_ip_address	= true

  tags = {
    Name = "hwan001-ec2"
    env  = var.env
  }
}

resource "aws_instance" "hwan001-ec2-prod" {
  count				= var.env == "prod" ? 3 : 0
  ami				= data.aws_ami.ubuntu.id
  instance_type			= "t2.micro"
  subnet_id			= aws_subnet.primary_az.id
  vpc_security_group_ids	= [aws_security_group.hwan001-sg.id]
  associate_public_ip_address	= true

  tags = {
    Name = "hwan001-ec2"
    env  = var.env
  }
}

 


내장함수

 내장 함수는 테라폼에 내장되어 있는 함수들로 여러 상황에서 유용하게 사용될 수 있으며, 아래와 같은 여러 이점들이 있다. 

  • 간결성 : 코드를 훨씬 간결하고 읽기 쉽게 만들 수 있다. 
  • 확장성 : 인프라 구조를 보다 쉽게 확장하거나 수정할 수 있다.
  • 유연성 : 다양한 데이터 타입(문자열, 숫자, 목록, 맵 등)을 처리하는데 유연성을 제공합니다.
  • 유효성 검사 : 내장 함수를 사용하면 입력값의 유효성을 쉽게 검사할 수 있다.
  • 기능성 : file이나 timestamp같은 일부 내장 함수는 특정 기능을 제공합니다.

 

아래는 많이 사용하는 내장 함수들이다. 

file : 입력받은 파일의 경로를 읽어 반환한다.

resource "aws_iam_policy" "iam_policy" {
  name        = "iam_policy"
  path        = "/"

  policy = file("policy.json")
}

 

format, formatlist : 문자열의 포맷을 정의 할 수 있다.

output "instance_id" {
  value = format("Instance ID is %s", aws_instance.hwan001-ec2.id)
}

 

element : 주어진 목록에서 특정 요소를 가져온다.

output "first_subnet" {
  value = element(aws_subnet.hwan001-subnet.*.id, 0)
}

 

lookup : 주어진 map 에서 특정 값을 찾는다.

output "instance_public_ip" {
  value = lookup(aws_instance.hwan001-ec2.*.attributes, "public_ip")
}

 

count.index : 현재 인덱스의 번호를 반환하며, 보통 반복적으로 리소스를 사용할 때 count와 같이 사용한다.

resource "aws_instance" "hwan001-ec2" {
  count         = 3
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  tags = {
    Name = "hwan001-ec2-instance-${count.index}"
  }
}

 

split, join : 문자열을 특정 구분자로 분리하거나 합칠 때 사용한다.

output "subnet_ids" {
  value = join(", ", aws_subnet.hwan001-subnet.*.id)
}

 

cidrhost :  네트워킹 설정을 할 때 유용하다. 예를 들면 여러 서브넷이 있는 VPC를 설정할 때, 각 서브넷의 IP 범위를 계산하는데 사용할 수 있다.

output "subnet_ip" {
  value = cidrhost("10.0.0.0/16", 4)
}

위 코드처럼 사용할 경우 10.0.0.0/16 의 4번째 호스트의 IP 주소(10.0.0.4)를 반환한다.

 

테라폼에서는 사용자가 함수를 직접 정의할 수는 없지만 다양한 함수들을 제공한다. 아래 문서에서 더 많은 정보를 얻을 수 있다.

https://developer.hashicorp.com/terraform/language/functions

 

Functions - Configuration Language | Terraform | HashiCorp Developer

An introduction to the built-in functions that you can use to transform and combine values in expressions.

developer.hashicorp.com


프로비저너

 프로바이더에서 제공되지 않는 파일 복사, 커맨드 등의 역할을 수행할 수 있지만 해당 코드로 인한 결과는 tfstate에 동기화되지 않는다.

따라서 실행 시 마다 실행의 결과가 항상 동일하지 않을 수도 있다.

 예를 들어 local-exec 프로비저너를 사용하면 테라폼을 활용해 리소스를 프로비저닝한 후 해당 리소스 내부를 앤서블 플레이북으로 프로비저닝 하는 등의 작업이 가능하다. 

provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_instance" "hwan001-ec2" {
  ami           = "ami-0c94855ba95c574c8"
  instance_type = "t2.micro"

  provisioner "local-exec" {
    command = "ansible-playbook -u ubuntu --private-key=${var.private_key_path} -i '${self.public_ip},' playbook.yml"
  }
}

 

하지만 해당 방식은 ssh 접속을 위한 정보가 필요하고, 여러 변수로 인해 안정적으로 프로비저닝되지 않을 수도 있다.

테라폼에서는 최근부터 terraform-provider-ansible를 제공한다. 

해당 프로바이더를 사용하면 tfstate 파일을 사용하여 인프라를 추적할 수 있기 때문에 좀 더 안정적으로 앤서블을 사용할 수 있다.

terraform {
  required_providers {
    ansible = {
      source = "ansible/ansible"
      version = "1.1.0"
    }
  }
}

provider "ansible" {}

resource "ansible_playbook" "playbook" {
  playbook   = "playbook.yml"
  name       = "host-1.example.com"
  replayable = true

  extra_vars = {
    var_a = "Some variable"
    var_b = "Another variable"
  }
}

 

자세한 정보는 아래링크에서 확인할 수 있다.

https://registry.terraform.io/providers/ansible/ansible/latest/docs

 

Terraform Registry

 

registry.terraform.io

https://github.com/ansible/terraform-provider-ansible/tree/main

 

GitHub - ansible/terraform-provider-ansible: community terraform provider for ansible

community terraform provider for ansible. Contribute to ansible/terraform-provider-ansible development by creating an account on GitHub.

github.com

 


Null Resource와 Terraform data

Null Resource

 Null Resource는 아무런 액션도 취하지 않는 리소스로 그 자체로는 아무런 효과가 없지만, 특정 조건에 따라 다른 리소스를 트리거하는 등의 복잡한 의존성이 필요한 경우에 유용하게 사용할 수 있다.

예를 들면 특정 조건에 따라 스크립트를 실행하거나, 다른 리소스가 변경될 때마다 새로운 리소스를 생성하는 등의 작업에 사용할 수 있다.

resource "null_resource" "example" {
  triggers = {
    always_run = "${timestamp()}"
  }

  provisioner "local-exec" {
    command = "echo Hello, World!"
  }
}

 

Null Resource는 주로 아래의 경우에 사용된다.

  • 프로비저닝 수행 과정에서 명령어 실행
  • 프로비저너와 함께 사용
  • 모듈, 반복문, 데이터 소스, 로컬 변수와 함께 사용
  • 출력을 위한 데이터 가공

 

예를 들어, AWS EC2 인스턴스를 프로비저닝하면서 웹서비스를 실행시키고 싶지만, 웹서비스 설정에는 노출되어야 하는 고정된 외부 IP가 포함된 구성이 필요하기 때문에 aws_eip 리소스를 생성해야 한다.

 

이런 경우 아래처럼 코드를 작성하면 aws_eip 부분에선 aws_instance.example.id가 필요하고, aws_instance 에선 aws_eip.myeip.public_ip가 필요하기 때문에 Cycle이 발생한다.

provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_security_group" "instance" {
  name = "hwan001-sg"

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "example" {
  ami                    = "ami-0c9c942bd7bf113a2"
  instance_type          = "t2.micro"
  subnet_id              = "subnet-000000" 
  private_ip             = "172.31.1.100"
  vpc_security_group_ids = [aws_security_group.instance.id]

  user_data = <<-EOF
              #!/bin/bash
              echo "Test page" > index.html
              nohup busybox httpd -f -p 80 &
              EOF

  tags = {
    Name = "Single-WebSrv"
  }

  provisioner "remote-exec" {
    inline = [
      "echo ${aws_eip.myeip.public_ip}"
     ]
  }
}

resource "aws_eip" "myeip" {
  instance = aws_instance.example.id
  associate_with_private_ip = "172.31.1.100"
}

output "public_ip" {
  value       = aws_instance.example.public_ip
}

 

이런 경우 Null Resource를 사용해서 2개의 리소스 생성에 시간 간격을 두어 해결할 수도 있다.

...

resource "aws_instance" "example" {
  ami                    = "ami-0c9c942bd7bf113a2"
  instance_type          = "t2.micro"
  subnet_id              = "subnet-000000" 
  private_ip             = "172.31.1.100"
  vpc_security_group_ids = [aws_security_group.instance.id]

  user_data = <<-EOF
              #!/bin/bash
              echo "Test page" > index.html
              nohup busybox httpd -f -p 80 &
              EOF

  tags = {
    Name = "Single-WebSrv"
  }
}

resource "aws_eip" "myeip" {
  instance = aws_instance.example.id
  associate_with_private_ip = "172.31.1.100"
}

resource "null_resource" "foo" {
  triggers = {
    ec2_id = aws_instance.example.id # instance의 id가 변경되는 경우 재실행
  }

  provisioner "remote-exec" {
    inline = [
      "echo ${aws_eip.myeip.public_ip}"
     ]
  }
}

output "public_ip" {
  value       = aws_instance.example.public_ip
}

 

Terraform_data

  Terraform 1.4버전 부터는 Null Resource를 대체하기 위해 terraform_data라는 리소스를 지원한다.

Null Resource를 사용하려면 null 공급자를 추가해줘야 한다. 하지만 Terraform Data는 해당 공급자를 추가하지 않아도 동작한다.

resource "terraform_data" "apply" {
  provisioner "local-exec" {
    command     = "echo ${aws_eip.myeip.public_ip}"
  }

  triggers_replace = [
    aws_instance.example.id
  ]
}

terraform_data 사용 시
null_resource 사용 시

좀 더 자세한 정보는 아래 링크 참고

https://developer.hashicorp.com/terraform/language/resources/terraform-data

 

The terraform_data Managed Resource Type | Terraform | HashiCorp Developer

Retrieves the root module output values from a Terraform state snapshot stored in a remote backend.

developer.hashicorp.com

 


moved 블록

 테라폼의 tfstate에서 리소스 주소의 이름이 변경되면 기존 리소스는 삭제되고 새로운 리소스가 생성된다. 하지만 기존 리소스의 이름만 변경하고 싶은 경우가 있다.

리소스의 이름은 변경되지만 이미 테라폼으로 프로비저닝된 환경을 그대로 유지하려고 하는 경우엔 moved 블록을 사용할 수 있다. (Terraform 1.1 이상부터 지원)

 

아래 코드로 ec2 instance를 생성했다.

provider "aws" {
  region = "ap-northeast-2" 
}

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"]  # Canonical
}

# EC2 Instance 생성
resource "aws_instance" "hwan001-ec2" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t2.micro"
  subnet_id                   = aws_subnet.primary_az.id
  vpc_security_group_ids      = [aws_security_group.hwan001-sg.id]
  associate_public_ip_address = true

  tags = {
    Name = "hwan001-ec2"
  }
}

 

해당 리소스 태그를 moved로 변경해보자.

resource "aws_instance" "hwan001-ec2-new" {
  ami				= data.aws_ami.ubuntu.id
  instance_type			= "t2.micro"
  subnet_id			= aws_subnet.primary_az.id
  vpc_security_group_ids	= [aws_security_group.hwan001-sg.id]
  associate_public_ip_address	= true

  tags = {
    Name = "hwan001-ec2-new"
  }
}

moved {
  from = aws_instance.hwan001-ec2
  to   = aws_instance.hwan001-ec2-new
}

moved를 사용해서 리소스의 삭제없이 인스턴스의 태그 정보를 변경했다. 

해당 작업 후 moved 부분을 제거해주면 된다.

 

(cc. moved를 사용해도 associate_public_ip_address이나 instance_type등을 변경하고 apply하면 리소스가 재생성된다.)

 


CLI를 위한 시스템 환경 변수

 Terraform에서는 환경 변수를 사용하여 다양한 설정을 구성할 수 있다.

  • TF_LOG : 로그 레벨 (TRACE, DEBUG, INFO, WARN, ERROR)
  • TF_LOG_PATH : 로그 파일의 경로, TF_LOG 환경 변수가 설정되어 있고 TF_LOG_PATH가 설정되어 있으면 로그를 기록한다.
  • TF_VAR_name : Terraform 변수의 값 (name은 설정하려는 변수의 이름, ex) TF_VAR_instance_type=t2.micro)
  • TF_INPUT : 사용자 입력 요청 여부를 제어, false일 경우 사용자 입력을 요청 안함
  • TF_IN_AUTOMATION : 자동화 도구 내에서 실행되고 있는지 여부, 이 환경 변수가 설정되어 있으면 자동화 도구와의 호환성을 향상시킨다.
  • AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN : AWS 프로바이더 인증 키
  • TF_CLI_ARGS / TF_CLI_ARGS_subcommand : 테라폼 실행 시 추가할 인수를 정의
  • TF_DATA_DIR : State 저장 백엔드 설정과 같은 작업 디렉터리별 데이터를 보관하는 위치를 지정

https://developer.hashicorp.com/terraform/cli/config/environment-variables

 

Environment Variables | Terraform | HashiCorp Developer

Learn to use environment variables to change Terraform's default behavior. Configure log content and output, set variables, and more.

developer.hashicorp.com

 


프로바이더

 테라폼은 terraform 바이너리 파일을 시작으로 로컬 환경에나 배포 서버와 같은 원격 환경에서 원하는 대상(프로바이더가 제공하는 API)을 호출하는 방식으로 실행된다. 각 프로바이더의 API 구현은 서로 다르지만 테라폼의 고유 문법으로 동일한 동작을 수행하도록 구현되어 있다.

https://malwareanalysis.tistory.com/619

 

다수의 프로바이더를 로컬 이름 지정

 required_providers 블록을 사용하여 다수의 프로바이더를 로컬 이름으로 지정해 사용할 수 있다.

예를 들면 아래는 여러 프로바이더가 제공해주는 동일한 http 관련 data 블록을 사용하는 예제이다.

terraform {
  required_providers {
    http = {
      source = "hashicorp/http"
      version = "3.4.0"
    }
    aws-http = {
      source = "terraform-aws-modules/http"
      version = "2.4.1"
    }
  }
}

data "http" "example1" {
  provider = http
  url = "https://checkpoint-api.hashicorp.com/v1/check/terraform"

  request_headers = {
    Accept = "application/json"
  }
}

data "http" "example2" {
  provider = http
  url = "https://checkpoint-api.hashicorp.com/v1/check/terraform"

  request_headers = {
    Accept = "application/json"
  }
}

 

해당 코드를 테라폼으로 apply하면 tfstate파일 내에서 해당 요청을 서로 다른 공급자로 얻어오는 걸 볼 수 있다. 

{
  ...
  "resources": [
    {
      "mode": "data",
      "type": "http",
      "name": "example1",
      "provider": "provider[\"registry.terraform.io/hashicorp/http\"]",
      "instances": [ ... ]
    },
    {
      "mode": "data",
      "type": "http",
      "name": "example2",
      "provider": "provider[\"registry.terraform.io/terraform-aws-modules/http\"]",
      "instances": [ ... ]
    }
  ],
  ...
}

 

단일 프로바이더의 다중 정의

 위의 경우와는 반대로 하나의 프로바이더를 여러번 정의해서 사용해야 하는 경우가 있다.

예를 들면 멀티 리전을 정의하는 경우인데, 아래처럼 alias를 활용해 같은 리소스 내부에서 리전을 지정해 줄 수 있다.

provider "aws" {
  region = "ap-southeast-1"
}

provider "aws" {
  alias = "seoul"
  region = "ap-northeast-2"
}

resource "aws_instance" "app_server1" {
  ami           = "ami-06b79cf2aee0d5c92"
  instance_type = "t2.micro"
}

resource "aws_instance" "app_server2" {
  provider      = aws.seoul
  ami           = "ami-0ea4d4b8dc1e46212"
  instance_type = "t2.micro"
}

 

하지만 해당 방식은 지역간 지연 시간, 고유 ID, 최종 일관성 등 여러가지 고려사항이 많고, 한 리전이 다운되었을 경우 전체 plan과 apply가 실패하기 때문에 다른 리전의 변경 사항도 적용할 수 없게 된다.

프로덕션 수준에서는 환경을 완전히 격리하여 서로 간의 영향도를 최소화하는 방법이 더 좋을 것 같다.


 

 

728x90
반응형
728x90
반응형

데이터 소스

 Terraform의 데이터 소스는 테라폼 설정 내에서 읽기 전용의 값들을 제공한다. 이 값을 활용하면 이미 존재하는 리소스의 세부사항이나 외부 데이터를 참조할 수 있다.

데이터 소스 블록은 아래처럼 data로 시작하고 ‘데이터 소스 유형’과 '이름'을 정의한다.

data "<리소스 유형>" "<이름>" {
  <인수> = <값>
}

# 참조 : data.<리소스 유형>.<이름>.<속성>
# 사용가능한 메타인수:
# depends_on : 종속성 선언
# count : 선언된 개수만큼 리소스를 생성
# for_each : map또는 set 타입 변수로 리소스 반복 생성
# lifecycle : 리소스 수명주기

 

예를 들면 아래 코드는 aws의 az 정보를 얻어와 각 az에 subnet을 생성할 수 있다.

data "aws_availability_zones" "available" {
  state = "available"
}

resource "aws_subnet" "primary_AZ" {
  availability_zone = data.aws_availability_zones.available.names[0]
}

resource "aws_subnet" "secondary_AZ" {
  availability_zone = data.aws_availability_zones.available.names[1]
}

 

연습 코드 : 

  • data 모듈로 az 이름 받아와서 vpc, subnet 생성하기
data "aws_availability_zones" "available" {
  state = "available"
}


resource "aws_vpc" "hwan001-vpc" {
    cidr_block = "10.10.0.0/16"

    tags = {
        Name = "hwan001-vpc"
    }
}

resource "aws_subnet" "primary_az" {
    vpc_id = aws_vpc.hwan001-vpc.id
    cidr_block =  "10.10.1.0/24"
    availability_zone = data.aws_availability_zones.available.names[0]
    tags = {
        Name = "hwan001-subnet-1"
    }
}

resource "aws_subnet" "secondary_az" {
    vpc_id = aws_vpc.hwan001-vpc.id
    cidr_block =  "10.10.2.0/24"
    availability_zone = data.aws_availability_zones.available.names[1]
    tags = {
        Name = "hwan001-subnet-2"
    }
}

 


변수(Variables) 종류 및 우선순위

변수 종류 : 

 변수 종류는 크게 기본 유형과 집합 유형으로 나뉜다.

기본 유형에는 string, number, bool, any가 있고, 집합 유형에는 list, map, set, object, tuple이 있다.

변수 정의할 땐 아래 메타인수가 사용 가능하다.

  • default : 값이 전달되지 않은 경우의 기본 값, default가 없으면 apply 시 변수에 대한 정보를 물어봄
  • type : 변수 유형 정의, string number bool list map set object tuple 와 유형을 지정하지 않으면 any 유형으로 간주
  • description : 입력 변수의 설명
  • validation : 변수 선언의 제약조건을 추가해 유효성 검사 규칙을 정의
  • sensitive : 민감한 변수 값으로 테라폼의 출력문에서 값 노출을 제한함 (암호 등 민감 데이터의 경우)
  • nullable : 변수에 값이 없어도 됨 (null 허용 여부)

사용 예시는 아래와 같다.

variable "string" {
  type        = string
  description = "var String"
  default     = "myString"
}

variable "number" {
  type    = number
  default = 123
}

variable "boolean" {
  default = true
}

variable "list" {
  default = [
    "google",
    "vmware",
    "amazon",
    "microsoft"
  ]
}

output "list_index_0" {
  value = var.list.0 # google, 1이면 vmware
}

output "list_all" {
  value = [
    for name in var.list : upper(name)
  ]
}

variable "map" { # Sorting
  default = {
    aws   = "amazon",
    azure = "microsoft",
    gcp   = "google"
  }
}

variable "set" { # Sorting
  type = set(string)
  default = [
    "google",
    "vmware",
    "amazon",
    "microsoft"
  ]
}

variable "object" {
  type = object({ name = string, age = number })
  default = {
    name = "abc"
    age  = 12
  }
}

variable "tuple" {
  type    = tuple([string, number, bool])
  default = ["abc", 123, true]
}

variable "ingress_rules" { # optional ( >= terraform 1.3.0)
  type = list(object({
    port        = number,
    description = optional(string),
    protocol    = optional(string, "tcp"),
  }))
  default = [
    { port = 80, description = "web" },
  { port = 53, protocol = "udp" }]
}

variable "my_password" {
  default   = "password"
  sensitive = true
}

 

우선 순위 : 

 변수가 선언되는 방식에 따라 우선순위가 존재한다.

실행 후 입력 < variable 블록의 default 값 < 환경 변수 (TF_VAR 변수 이름) < terraform.tfvars < *.auto.tfvars < *.auto.tfvars.json < CLI 실행 시 -var 인수에 지정 또는 -var-file로 파일 지정

오른쪽으로 갈수록 우선순위가 높다. 예를들어 변수의 값을 출력해주는 코드가 있을 때, terraform.tfvars 내부 변수에 1이라는 값이 정의되어 있고, 실행후에 3이라는 값을 입력 한다면 결과는 1이 나오게 된다.

# main.tf 
variable "my_var" {
  default = "var2"
}

resource "local_file" "abc" {
  content  = var.my_var
  filename = "${path.module}/abc.txt"
}

#terraform.tf
my_var="var4"


기본 문법 

local : 로컬에서만 사용하는 변수

output : 프로비저닝 수행 결과의 속성 값을 출력

반복문 : count, for each, for expression 등 여러개의 데이터를 한개의 리소스로 반복적으로 생성

# count
resource "local_file" "abc" {
  count    = 5
  content  = "abc"
  filename = "${path.module}/abc.txt"
}


# for each
resource "local_file" "abc" {
  for_each = {
    a = "content a"
    b = "content b"
  }
  content  = each.value
  filename = "${path.module}/${each.key}.txt"
}


# for
variable "names" {
  default = ["a", "b", "c"]
}

resource "local_file" "abc" {
  content  = jsonencode([for s in var.names : upper(s)]) # 결과 : ["A", "B", "C"]
  filename = "${path.module}/abc.txt"
}

# for의 다양한 활용
variable "names" {
  type    = list(string)
  default = ["a", "b"]
}

output "A_upper_value" {
  value = [for v in var.names : upper(v)]
}

output "B_index_and_value" {
  value = [for i, v in var.names : "${i} is ${v}"]
}

output "C_make_object" {
  value = { for v in var.names : v => upper(v) }
}

output "D_with_filter" {
  value = [for v in var.names : upper(v) if v != "a"]
}

 

Dynamic : 리소스 내부 속성 블록 동적인 블록으로 생성한다. dynamic을 사용할 경우 특정 리소스 블록 내부에서 하나의 속성 블록에서 여러 개의 속성을 부여할 수 있게 된다.

# 일반적인 속성 부여
resource "provider_resource" "name" {
  name = "some_resource"

  some_setting {
    key = a_value
  }

  some_setting {
    key = b_value
  }

  some_setting {
    key = c_value
  }

  some_setting {
    key = d_value
  }
}

# dynamic을 활용한 부여
resource "provider_resource" "name" {
  name = "some_resource"

  dynamic "some_setting" {
    for_each = {
      a_key = a_value
      b_key = b_value
      c_key = c_value
      d_key = d_value
    }

    content {
      key = some_setting.value
    }
  }
}

 

연습 코드 :

  • 입력받은 수 만큼 count로 sqs에 큐 생성하기
provider "aws" {
  region = "ap-northeast-2" 
}

variable "number_of_queue" {
    type = number
}

resource "aws_sqs_queue" "main_queue" {
    count                     = var.number_of_queue
    name                      = "queue-${count.index+1}"
    delay_seconds             = 0
    max_message_size          = 1024
    message_retention_seconds = 345600
    visibility_timeout_seconds = 60
}

 

  • dynamic을 활용한  security group 생성하기
variable "ingress_rules" {
    type = list(object(
        {
            from_port   = number
            to_port     = number
            protocol    = string
            cidr_blocks = list(string)
        }
    ))

    default = [
        {
            from_port   = 22
            to_port     = 22
            protocol    = "tcp"
            cidr_blocks = ["0.0.0.0/0"]
        },
        {
            from_port   = 80
            to_port     = 80
            protocol    = "tcp"
            cidr_blocks = ["0.0.0.0/0"]
        },
        {
            from_port   = 443
            to_port     = 443
            protocol    = "tcp"
            cidr_blocks = ["0.0.0.0/0"]
        },
        {
            from_port   = 8080
            to_port     = 8080
            protocol    = "tcp"
            cidr_blocks = ["0.0.0.0/0"]
        }
    ]
}

resource "aws_security_group" "hwan001-sg" {
    description = "hwan001 Security Group"
    vpc_id      = aws_vpc.hwan001-vpc.id
    
    dynamic "ingress" {
        for_each = var.ingress_rules
        content {
            from_port   = ingress.value.from_port
            to_port     = ingress.value.to_port
            protocol    = ingress.value.protocol
            cidr_blocks = ingress.value.cidr_blocks
        }
    }

    egress {
        from_port       = 0
        to_port         = 0
        protocol        = "-1"
        cidr_blocks     = ["0.0.0.0/0"]
    }

    tags = {
        Name = "hwan001-sg"
    }
}

도전 과제

  • 리전 내에서 사용 가능한 가용영역 목록 가져오기를 사용한 VPC 리소스 생성 실습 진행
  • 위 3개 코드 파일 내용에 리소스의 이름(myvpc, mysubnet1 등)을 반드시! 꼭! 자신의 닉네임으로 변경해서 배포 실습해보세요!
  • 입력변수를 활용해서 리소스(어떤 리소스든지 상관없음)를 배포해보고, 해당 코드를 정리해주세요!
  • local를 활용해서 리소스(어떤 리소스든지 상관없음)를 배포해보고, 해당 코드를 정리해주세요!
  • count, for_each, for, dynamic문 을 활용해서 리소스(어떤 리소스든지 상관없음)를 배포해보고, 해당 코드를 정리해주세요!

 

network.tf :

  • data를 사용해 az 이름 가져오기
  • vpc, subnet 생성하기
data "aws_availability_zones" "available" {
  state = "available"
}


resource "aws_vpc" "hwan001-vpc" {
    cidr_block = "10.10.0.0/16"

    tags = {
        Name = "hwan001-vpc"
    }
}

resource "aws_subnet" "primary_az" {
    vpc_id = aws_vpc.hwan001-vpc.id
    cidr_block =  "10.10.1.0/24"
    availability_zone = data.aws_availability_zones.available.names[0]
    tags = {
        Name = "hwan001-subnet-1"
    }
}

resource "aws_subnet" "secondary_az" {
    vpc_id = aws_vpc.hwan001-vpc.id
    cidr_block =  "10.10.2.0/24"
    availability_zone = data.aws_availability_zones.available.names[1]
    tags = {
        Name = "hwan001-subnet-2"
    }
}

 

sg.tf : 

  • 다이나믹을 사용해서 여러 개의  ingress rule 정의하기
  • 보안 그룹 생성
variable "ingress_rules" {
    type = list(object(
        {
            from_port   = number
            to_port     = number
            protocol    = string
            cidr_blocks = list(string)
        }
    ))

    default = [
        {
            from_port   = 22
            to_port     = 22
            protocol    = "tcp"
            cidr_blocks = ["0.0.0.0/0"]
        },
        {
            from_port   = 80
            to_port     = 80
            protocol    = "tcp"
            cidr_blocks = ["0.0.0.0/0"]
        },
        {
            from_port   = 443
            to_port     = 443
            protocol    = "tcp"
            cidr_blocks = ["0.0.0.0/0"]
        },
        {
            from_port   = 8080
            to_port     = 8080
            protocol    = "tcp"
            cidr_blocks = ["0.0.0.0/0"]
        }
    ]
}

resource "aws_security_group" "hwan001-sg" {
    description = "hwan001 Security Group"
    vpc_id      = aws_vpc.hwan001-vpc.id
    
    dynamic "ingress" {
        for_each = var.ingress_rules
        content {
            from_port   = ingress.value.from_port
            to_port     = ingress.value.to_port
            protocol    = ingress.value.protocol
            cidr_blocks = ingress.value.cidr_blocks
        }
    }

    egress {
        from_port       = 0
        to_port         = 0
        protocol        = "-1"
        cidr_blocks     = ["0.0.0.0/0"]
    }

    tags = {
        Name = "hwan001-sg"
    }
}

 

main.tf : 

  • ubuntu 20.04 공식 ami 정보를 data로 가져오기
  • 해당 ami를 사용해서 ec2 인스턴스 띄우기 (subnet, sg는 위에서 생성한 리소스로 사용)
provider "aws" {
  region = "ap-northeast-2" 
}

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"]  # Canonical
}

# EC2 Instance 생성
resource "aws_instance" "hwan001-ec2" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t2.micro"
  subnet_id                   = aws_subnet.primary_az.id
  vpc_security_group_ids      = [aws_security_group.hwan001-sg.id]
  associate_public_ip_address = true

  tags = {
    Name = "hwan001-ec2"
  }
}

 

결과 : 

생성된 서브넷
생성된 ec2
생성된 보안 그룹

728x90
반응형
728x90
반응형

Terraform

 HashiCorp사의 Terraform은 버전화, 재사용 및 공유할 수 있는 사람이 읽을 수 있는 구성 파일에서 클라우드 및 온프레미스 리소스를 모두 정의할 수 있는 코드형 인프라(IaC) 도구로 Amazon Web Services(AWS), Azure, Google Cloud Platform(GCP), Kubernetes, Helm, GitHub, Splunk, DataDog 등 수천여개의 다양한 Provider를 제공한다.

 

Provider

 테라폼을 적용할 대상으로 한번에 하나의 프로비저닝만 가능하며 terraform init을 통해 설치된다. (aws 구성을 azure로 변경하는 등의 작업은 불가함, 프로바이더에 대한 자세한 정보는 아래 링크 참조)

https://registry.terraform.io/browse/providers 

 

Terraform Registry

 

registry.terraform.io

원하는 프로바이터를 선택하고 오른쪽 상단의 USE PROVIDER 버튼을 누르면 간단한 사용방법이 나온다. 

 

Workflow and Terminology used in Terraform

 테라폼은 크게 write -> plan -> apply의 과정을 거쳐 인프라를 프로비저닝한다.

  • write : 여러 클라우드 공급자 및 서비스에 걸쳐 있을 수 있는 리소스를 정의한다. 
  • plan :존 인프라 및 구성(tfstate)을 기반으로 생성, 업데이트 또는 파괴할 인프라를 설명하는 실행 계획을 생성한다.
  • apply : 승인 시 Terraform은 모든 리소스 종속성을 고려하여 올바른 순서로 제안된 작업을 수행한다.

https://mindmajix.com/terraform-tutorial

 

 아래는 테라폼에서 사용하는 용어들이다.

  • resourece : 실제로 생성할 인프라 자원을 의미
  • output : 인프라를 프로비저닝 한 후에 생성된 자원을 output 부분으로 출력할 수 있음
  • backend : terraform의 상태를 저장할 공간 지정 (내부 / 외부 모두 가능 , 이 기능으로 다른사람들과 협업 가능)
  • module : 공통적으로 활용할 수 있는 인프라 코드를 한곳으로 모아 정의하는 부분 (변수만 바꿔서 동일한 리소스를 쉽게 생성 가능)
  • remote state : VPC , IAM 등과 같이 여러 서비스가 공통으로 사용하는 것이 가능 ( ftstate 파일이 저장돼 있는 backend 정보를 명시하면, trerraform이 backend에서 output 정보들을 가져옴 )
  • .tfstate 파일 : 테라폼이 인프라스트럭처의 상태를 추적하고 관리하는 핵심 도구로 아래와 같은 역할을 수행한다.
  1. 인프라스트럭처 상태 추적: 파일을 통해 프로비저닝된 리소스의 상태를 기록하고, 변경 사항을 추적하며, 이전 상태와의 차이를 분석하여 필요한 변경을 식별합니다. (plan 시 달라지는 부분을 확인할 수 있음)
  2. 변경 관리: 변경 사항을 .tfstate 파일에 반영하고 apply 시 이 파일을 사용하여 변경 사항을 적용한다. 이런 방식으로 인프라스트럭처를 안전하게 변경하고 일관성 있게 유지할 수 있다.
  3. 협업 및 공유: .tfstate 파일은 팀 간 협업과 공유를 지원한다. 팀원들은 동일한 .tfstate 파일(백엔드 등)에 액세스하여 상태를 공유하고, 변경 사항을 추적하고 충돌을 방지할 수 있다.
  4. 롤백 및 복구: .tfstate 파일은 변경 사항을 롤백하고 이전 상태로 복구하는 데 사용될 수 있다.

 


환경 구축

테라폼 설치하기

 테라폼은 여러 운영체제에서 사용할 수 있지만, Mac을 사용하기 때문에 brew와 tfenv를 사용해서 설치해보려고 한다.

 ftenv를 사용하면 테라폼의 버전을 쉽게 관리할 수 있다.

# tfenv 설치
brew install tfenv

# 테라폼 설치
tfenv list-remote # 설치 가능 버전 확인
tfenv install 1.5.1
tfenv use 1.5.1
tfenv list # tfenv로 설치한 버전 확인

# 테라폼 버전 정보 확인
terraform version

 

visual studio code 설치하기

 코드를 수정하기 위한 에디터로 vs code를 사용했다. 설치는 아래처럼 brew를 활용해도 좋지만 웹(https://code.visualstudio.com)에서 다운로드 받아 설치할 수도 있다.

vscode를 설치한 후엔 code 명령어를 사용할 수 있도록 Path에 추가해주면 좋다.(https://velog.io/@mingkyme/VSCode-Command-line-%EC%84%A4%EC%B9%98-code-%EB%AA%85%EB%A0%B9%EC%96%B4)

brew install visual-studio-code
 

Visual Studio Code - Code Editing. Redefined

Visual Studio Code is a code editor redefined and optimized for building and debugging modern web and cloud applications.  Visual Studio Code is free and available on your favorite platform - Linux, macOS, and Windows.

code.visualstudio.com

 

awscli 설치하기

 aws를 cli(command line interface)로 다루기 위한 툴로 brew를 사용해서 설치할 수 있다.

brew install awscli

 

유용한 도구 설치

 아래 툴들을 추가로 설치하면 작업할 때 좀 더 유용하다.

brew install tree, jq, watch

 

graphviz (dot) 플러그인 설치하기

 vscode의 마켓플레이스에서 해당 플러그인을 추가로 설치해주면, 오른쪽처럼 .dot파일을 그래프로 볼 수 있다. 

.dot 파일은 terraform graph 명령을 사용해 생성할 수 있기 때문에 위 플러그인을 사용하면 테라폼 코드의 구조를 그래프로 확인할 수 있다.

 


테라폼 사용

ec2 웹서버 배포하기

 테라폼을 사용해서 ec2에 아파치 웹 서비스를 배포해보자. 

provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_instance" "example" {
  ami                    = "ami-0c9c942bd7bf113a2"
  instance_type          = "t2.micro"
  vpc_security_group_ids = [aws_security_group.instance.id]

  user_data = <<-EOF
              #!/bin/bash
              echo "Hello, T1012 Study 8080" > index.html
              nohup busybox httpd -f -p 8080 &
              EOF

  user_data_replace_on_change = true # true일 경우 인스턴스를 재생성한다.

  tags = {
    Name = "Single-WebSrv"
  }
}

resource "aws_security_group" "instance" {
  name = var.security_group_name

  ingress {
    from_port   = 8080
    to_port     = 8080
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

variable "security_group_name" {
  description = "The name of the security group"
  type        = string
  default     = "terraform-example-instance"
}

output "public_ip" {
  value       = aws_instance.example.public_ip
  description = "The public IP of the Instance"
}

 

 위 코드를 apply하면, aws 서울 리전(ap-northeast-2)에 우분투(ami-0c9c942bd7bf113a2) 이미지를 사용한 t2.micro 유형의 ec2 인스턴스를 Single-WebSrv라는 이름으로 보안 그룹을 적용해서 생성한다.

 user_data에 아래 코드를 넣어 줬기 때문에 인스턴스가 실행되면서 아파치 웹 서버(8080번 포트)로 index.html을 띄운다.

#!/bin/bash
echo "Hello, T1012 Study 8080" > index.html
nohup busybox httpd -f -p 8080 &

 

 vpc와 subnet은 default를 사용하므로, 해당 리소스가 클라우드 계정 내에 없다면 생성이 실패할 수 도 있다.

이럴 경우 아래 명령을 실행해주자.

# default VPC를 생성
aws ec2 create-default-vpc

# default Subnet 생성
aws ec2 create-default-subnet --availability-zone ap-northeast-2a
aws ec2 create-default-subnet --availability-zone ap-northeast-2b
aws ec2 create-default-subnet --availability-zone ap-northeast-2c
aws ec2 create-default-subnet --availability-zone ap-northeast-2d

 

위의 모든 과정은 ~/.aws/credential에 크레덴셜 정보가 있어야 가능하다.

만약 없다면 aws configre 명령어로 설정해주면 된다.


lifecycle

 테라폼은 기본적으로 immutable한 인프라스트럭쳐 관리를 지향하기 때문에 기본 수명주기는 삭제 후 생성이지만, 작업 시 리소스를 제거하면 안되는 경우가 종종 있다.

lifecyle은 이런 경우에 리소스의 기본 수명주기를 작업자가 의도적으로 변경할 수 있도록하는 메타인수다.

메타인수를 사용하면 아래 기능들이 가능하다.

  • create_before_destroy (bool): 리소스 수정 시 신규 리소스를 우선 생성하고 기존 리소스를 삭제
  • prevent_destroy (bool): 해당 리소스를 삭제 Destroy 하려 할 때 명시적으로 거부
  • ignore_changes (list): 리소스 요소에 선언된 인수의 변경 사항을 테라폼 실행 시 무시
  • precondition: 리소스 요소에 선언해 인수의 조건을 검증
  • postcondition: Plan과 Apply 이후의 결과를 속성 값으로 검증

하지만 위의 메타인수들을 잘못 사용하면 적용은 잘 되지만 실제로는 리소스가 사라지는 경우가 있다.

 ex) 동일한 리소스를 수정할 때 create_before_destroy 옵션을 키고 적용하면 생성 후 삭제하게 되는데, 이 때 기존 리소스가 삭제됨

제대로 이해하고 사용하면 유용하지만, 잘못 사용할 경우 리스크가 있는 기능인 것 같다.

728x90
반응형
728x90
반응형

프로그램을 만들면서 Python 서버와 REST로 연결하기 위해 라이브러리를 찾아봤다.

구글 검색을 통해 C++로 작성된 HTTP 클라이언트/서버 애플리케이션을 개발할 때 도움를 주는 C++ REST SDK (또는 Casablanca) 라이브러리를 찾았다.

 해당 라이브러리는 microsoft의 공식 라이브러리로 깃 허브에 올라와 있었기 때문에, 빌드를 위해 아래 Dockerfile을 작성했다.

 

casablanka.Dockerfile

FROM ubuntu:latest AS env

RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y sudo
RUN apt-get install -y g++ git libboost-atomic-dev libboost-thread-dev libboost-system-dev libboost-date-time-dev libboost-regex-dev libboost-filesystem-dev libboost-random-dev libboost-chrono-dev libboost-serialization-dev libwebsocketpp-dev openssl libssl-dev ninja-build

RUN git clone https://github.com/microsoft/cpprestsdk.git
RUN apt-get install -y cmake zlib1g-dev

WORKDIR cpprestsdk
RUN mkdir build && cd build
RUN cmake . -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=1 -DCMAKE_CXX_FLAGS="-Wno-error" -DCMAKE_CXX_FLAGS="-Wno-format-truncation"

RUN make -j$(nproc)
RUN sudo make install

 

위 코드를 사용해 docker로 빌드하면 .so 파일들이 나온다.

하지만 지금은 윈도우 용 프로그램을 만들고 있기 때문에 visual studio에서 사용할 수 있도록 설정을 다시해봐야 할 것 같다.

728x90
반응형
728x90
반응형

** 아래 내용에 아직 정리 안된 서비스들도 많지만 공부하면서 하나씩 추가로 정리할 예정입니다.

 

AWS (Amazon Web Services)

 AWS를 공부하면서 어떤 제품들이 있는지 정리를 해보고 싶어졌다.

하지만 아래 이미지에 있는 기초 서비스들 외에도 많은 서비스들이 있고, 새로운 서비스가 계속 출시되기 때문에 모든 서비스를 정리하진 못했다. 추후에 하나씩 공부하면서 정리할 예정이다.

아래 이미지는 AWS 홈페이지의 서비스 카테고리를 기준으로 만들었는데, 정리하면서 같이 업데이트해보려고 한다.

  • EC2 : 가상 머신 역할로 Amazon의 가장 중심 서비스이다.
  • S3 : 정적 파일 (사진, 비디오, 문서 등 또는 frontend 코드와 Lambda 함수 코드도 해당) 스토리지 서비스의 솔루션
  • IAM (Identity and Access Management) : AWS 서비스 관련 액세스와 권한 설정하는 “Key(키/열쇠)” 관리 서비스
  • Route 53 : DNS 설정 관련 서비스
  • Elastic Beanstalk :  Heroku와 비슷한 PaaS(Platform as a Service) 서비스
  • CloudFront (CDN) : 지역적으로 분산된 서버들을 통해 웹 서버와 사용자 사이에 가장 가까운 서버를 활용하여 페이지 콘텐츠 로드 지연을 최소화하는 서비스
  • RDS (Relational Database Service) : MySQL, Oracle DB, PostgreSQL과 같은 관계형 데이터베이스 엔진을 제공하는 서비스
  • Lambda (serverless compute service) : 백엔드 없이 이벤트가 있을 때마다 function 실행될 수 있는 기능, 호출 시 에만 요금이 부과되어 저렴함
  • Lightsail : one-click 서버 세팅 서비스로 저렴한 가격과 확장성, 편의성을 갖춤
  • EMR (Elastic MapReduce) :비즈니스, 연구원, 데이터 분석가 및 개발자가 막대한 양의 데이터를 간편하게, 비용 효율적으로 처리할 수 있는 웹 서비스
  • KMS (Key Management Service) : 
  • Region : AWS의 모든 서비스가 존재하는 물리적인 위치로 실제 위치와 가까울수록 속도가 빠르다
  • AZ (Available Zone) : 리전 내에 존재하는 가용 영역으로 실제 데이터가 존재하는 데이터 센터이며, HA를 제공함
  • Direct Connect : 외부의 데이터 센터나 시스템과 AWS를 연결하기위한 서비스
  • VPC (Virtual Private Cloud) :  사용자가 정의한 가상 네트워크로 데이터 센터에서 운영하는 네트워크와 유사함
  • VPC Peering : 두 VPC 간의 트래픽 라우팅을 위한 네트워크, 다른 사용자의 VPC와 연결할 수 있다.
  • ELB (Elastic Load Balancer) : 네트워크 트래픽을 제어하며 아래 와같이 나눠짐

  • Classic Load Balancer : 

  • Cognito : 수백만명의 사용자 인증 관리와 OAuth를 지원하는 서비스 
  • Amplify : 프론트/백 엔드, 호스팅, 배포까지 풀스택으로 애플리케이션을 개발하도록 돕는 서비스의 집합
  • Appsync : 단일 엔드포인트를 통해 애플리케이션 개발을 간소화하는 서버리스 GraphQL 및 게시/구독 API를 생성하여 데이터를 안전하게 쿼리, 업데이트 또는 게시
  • Direct Connect : 표준 이더넷 광섬유 케이블을 통해 내부 네트워크를 AWS Direct Connect 위치에 연결하여 대량의 정보를 사용자의 온프레미스 서버와 안전하고 빠르게 송수신
    https://docs.aws.amazon.com/ko_kr/directconnect/latest/UserGuide/Welcome.html

 


컴퓨팅 서비스

EC2 (Elastic Compute Cloud) 

 

  • 가상의 컴퓨터 자원(인스턴스) 을 제공하는 IaaS(Infrastructure as a Service) 서비스
  • 사용한 만큼 비용을 지불하는 형태
  • 클라우드에서 자원의 규모를 원하는 대로 변경 가능
  • 안정성을 위해 여러 리전과 가용영역에 배포됨

 

ECS (Elastic Container Service)

 

  • 클러스터에서 컨테이너를 손쉽게 실행, 중지 및 관리할 수 있는 확장성이 뛰어나고 빠른 컨테이너 관리 서비스

 

Lambda (Serverless)

 

  • 애플리케이션, 백엔드에 대한 코드를 별도의 설정이나 구축없이 실행하는 서비스
  • Serverless 아키텍처에 적합
  • 사용한 만큼 비용이 지불되어 비교적 저렴하게 서비스 운영이 가능
  • 유지 보수, 용량 프로비저닝, 오토 스케일링, 모니터링 및 로깅 같은 자원 관리를 자체적으로 수행

 

AWS Auto Scailing 

 

  • 부하 예측, 예약된 조정 작업, 최대 용량 동작
  • 사용자의 애플리케이션이 고부하 상태일 때 자동으로 추가 인스턴스를 생성하여 부하를 분산할 수 있음
  • 애플리케이션의 부하가 감소하면 자동으로 인스턴스를 제거하여 비용을 절감

 


네트워킹 서비스  (Networking Service)

VPC (Virtual Private Cloud)

 

  • 클라우드 내에서의 가상 네트워크 구축 서비스
  • IP주소 범위 선택, 라우팅 테이블/ 게이트웨이 구성, 서브넷 등 가상 네트워킹 환경 제어 (IPv4, IPv6 사용가능)

 

Route 53 (DNS)

 

  • AWS에서 제공하는 Domain Name System 서비스
  • 도메인 이름을 구매하거나 관리할 수 있고, 도메인에 대한 DNS 설정을 자동으로 구성 가능
  • 클라우드 내부의 사용자를 외부의 인프라로 전달 가능

 

CloudFront (CDN)

 

  • 데이터, 동영상, 애플리케이션 및 API를 전 세계 고객에게 안전하게 전송 CDN 서비스
  • S3, EC2, Elastic Load Balancing, Route 53 등과 같은 AWS 서비스와 함께 운영

 


스토리지 서비스  (Storage Service)

S3 (Simple Storage Service)

 

  • 정적 파일 스토리지 서비스 (사진, 비디오, 문서, 코드 등)
  • 사용자는 URL을 통해 파일 접근이 가능
  • 엑세스 컨트롤 기능 제공
  • HTTP 프로토콜과 연동 가능 (파일서버)
  • CloudFront와 연동하여 S3에 저장된 파일을 빠르게 전달 가능

 


데이터 베이스 서비스  (Database Service)

RDS (Relational Database Service)

 

  • 관계형 데이터베이스 이용할 수 있는 서비스
  • DB 설정, 패치, 백업 등의 작업을 AWS에서 처리
  • Amazon Aurora, MySQL, MariaDB, PostgreSQL, Oracle, SQL Server 등 RDBMS 서비스 지원

 

DynamoDB

 

  • key-value형태의 NoSQL 데이터베이스 서비스
  • 데이터 규모와 관계없이 데이터를 저장 및 검색하고 처리할 수 있는 데이터베이스 테이블을 생성할 수 있음

 

ElasticCache

 

  • Database Caching 서비스
  • Memcached, Redis 호환 가능

 


관리 도구  (Management Tools)

CloudWatch

 

  • AWS 서비스들과 관련된 모니터링 및 알람 설정 서비스
  • 특정 금액 초과, EC2의 CPU 사용률 등의 상황을 설정하여 메일 등으로 알려줄 수 있음

 

CloudFormation

 

  • AWS 서비스 생성 및 배포 자동화 템플릿 서비스
  • 미리 만들어놓은 Json 또는 직접 작성된 템플릿을 이용하여 서비스 생성 및 관리할 수 있음

 


보안, 자격증명 및 규정 준수

Cognito

 

  • OAuth 2.0, SAML 2.0 및 OpenID Connect와 같은 자격 증명 및 액세스 관리 표준을 지원
  • 수백만 명의 사용자로 확장되는 안전한 사용자 디렉터리
  • 사용자 풀은 인프라를 사전 구축할 필요 없이 자격 증명 환경에 용량을 제공
  • 암호화 및 멀티 팩터 인증(MFA) 기능
  • 기본 제공 UI 및 여러 자격 증명 공급자와 연동하여 앱에 사용자 로그인, 가입 및 액세스 제어를 추가 가능

 


용어

아래는 AWS 공식 용어집이다.

해당 내용도 공부하면서 하나씩 추가할 예정이다.

 

https://docs.aws.amazon.com/ko_kr/general/latest/gr/glos-chap.html

 

AWS 용어집 - AWS 일반 참조

이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.

docs.aws.amazon.com

  • 인스턴스 : Amazon EC2 서비스의인스턴스 컴퓨팅 자원으로 EC2 인스턴스와 컨테이너 인스턴스 등 앞에 다른 내용을 붙여 다른 유형의 인스턴스와 구별함
  • 온디맨드 : 과금 방식에 대한 용어로 사용한 시간만큼 비용을 지불하는 방식을 의미함

 

 

 

 

728x90
반응형

'DevOps > AWS' 카테고리의 다른 글

AWS 프리티어 회원 가입 및 설정(CloudWatch, MFA)  (0) 2022.04.30
728x90
반응형

로드맵을 기준으로 DevOps 분야에 대한 공부 방향성과 현재 지식 수준을 점검해보려고 한다.

기준은 구글에 검색해서 나온 이미지 중 정리가 잘 되었다고 생각한 이미지이다.

https://dev.to/ankit01oss/the-complete-devops-roadmap-28n1

 

The complete DevOps roadmap 🚀

Hi there, This is Ankit, your friendly DevOps content curator. I read a lot of articles about...

dev.to

 

기본적인 내용이나 활용 등 어느정도 알고 있다고 생각한 항목은 내용을 작성했고, 애매하게 알고있다고 생각한 내용은 주황색, 잘 모른다고 생각한 항목은 빨간색으로 강조했다.


Learn a Programming Language

  • c
    : 포인터, 구조체, 함수 등 기본적인 개념 이해
    : Windows API 활용 및 DLL 작성 가능
  • c++
    : 클래스, 템플릿, STD 등 기본 문법 활용이 가능
  • Python
    : 기본 문법 및 자료 구조 활용 능숙
    : 리스트 컴프리헨션, 람다 함수, 데코레이터, 비동기 활용 가능
    : 다양한 패키지 활용 경험
  • Ruby : 모름
  • Go
    : 기본 문법 및 고루틴 이해
    : 예제 수준 작성 가능 
  • Rust : 모름
  • JavaScript/Node.js
    : 기본적인 JavaSctript  및 Ajax 작성 가능
    : 간단한 Node.js 백엔드 구축 및 기동 가능

 


Understand difference OS concepts

  • Networking
    : 라우터, 스위치, 허브 개념
    : OSI 7 Layer 이해
    : 랜, 구리, 광케이블 융착 가능
    : 채널먹스, MSPP 운용 경험
    : TCP/ UDP 개념 이해
  • Sockets
    : c, Python 소켓 프로그래밍 가능
    : Raw 소켓 테스트 수준으로 가능
  • I/O Management : 
  • Virtualization : 하이퍼바이저, VM?
  • Memory/ Storage : 
  • File Systems :
  • POSIX Basics : 
  • Process management : 
  • Startup management (initd) : 
  • Service management (systemd) : 
  • Threads and Concurrency : 

 


Operating System

  • Linux (Debian, SUSE Linux, Fedora, Ubuntu, CentOS, Rocky, RHEL)
    : rpm build.spec 수정/작성 가능, yum repository 구축 가능, rpm/ deb 버전 별 설치 가능
    : 서비스, 네트워크 인터페이스, NTP, locale, iptables 등 명령어 능숙
    : 유저별 그룹관리, 계정 생성 및 ssh 연동, 자원 관리 
    : Clonezilla 활용 가능
    : 쉘 스트립팅 가능
  • Unix (FreeBSD, OpenBSD, NetBSD) : OpenBSD만 설치 해봄
  • Windows
    : PowerShell 스크립트 가능 (COM 포트 시리얼 통신 등)
    : Windows API 활용 가능
    : DLL injection, Global hooking 코드 작성 경험 있음
    : 커널 디버깅 환경 구축 가능 (windbg, 가상 머신)
    : 필터/HID 드라이버 기초 개념 이해 및 예제 수준 작성 가능
  • Windows Server : 설치 및 IIS 서버 구축, 사설 ssl 인증서 발급 가능

 


Learn to live in Terminal

  • Bash Scripting
  • Vim/ Nano/ PowerShell/ Emacs
  • Compiling apps from source : gcc 
  • System Performance : nmon, iostat, sar, vmstat
  • Others : strace, dtrace, systemtap, uname, df, history
  • Nerwork : nmap, tcpdump, ping, mtr, traceroute, airmon, airodump, dig, iptables, netstat
  • Process Monitoring : ps, top, htop, atop, isof
  • Text Manipulation Tools : awk, sed, grep, sort, uniq, cat, cut, echo, fmt, tr, ni, egrep, fgrep, wc

 


Networking, Security and Protocols

  • Emails : SMTP, IMAPS, POP3S, DMARC, SPF
    : 툴을 활용한 메일서버 구축, 구글 smtp와 연동 등 작업은 가능, 프로토콜 구조 등을 알지는 못함
  • Protocols : HTTP, HTTPS, FTP, SSL/TLS, SSH
    : 각자 개념 등에 대해 어느정도 설명이나 이해는 가능하지만 프로토콜 구조를 완벽하게 알지 못함
  • Port Forwarding : 공유기, 툴 등을 활용하여 포트포워딩 가능
  • Domain Keys : 


What is and How to setup ___

  • reverse Proxy : 대략적으로 이해
  • caching server : 
  • Load Balancer : 개념 이해 및 간단한 활용 가능
  • Forward Proxy :
  • firewall : 개념 및 iptables 등 기본 방화벽 활용 가능, inbound/ outbound 정책 추가 가능
  • webserver : IIS, Nginx, Apache, Tomcat, caddy
    : 정적 웹서버 구축 및 config 설정 가능

 


Learn Infrastructure as Code

  • Containers : Docker, LXC
    : Docker 사용 가능, Dockerfile 작성 가능, 네트워크 및 특권 설정 가능, docker compose 일부 활용 가능
  • Configuration Management : Ansible, Chef, SaltStack, Puppet
    : 어떤 용도이고 각 도구 별 차이점은 대략적으로 알고있지만 실제 사용 경험이 적거나 없음
  • Container Orchestration : Kubernetes, Docker swarm, mesos, nomad
    : 쿠버네티스 클러스터, minikube 구축 가능, pod/deployment/service/CNI 등 기본 용어와 개념은 알지만 활용 미숙함
  • Infrastructure Procisioning : Terraform, CloudFormation, Pulum
    : Terraform의 Write-> Plan-> Apply 구조와 작성된 tf 파일 활용은 가능하지만 이해도가 낮음

 


Learn some CI/CD Tools

  • Gitlab CI : 구축 및 기본 기능 활용 가능
  • Jenkins : 구축, 플러그인, 노드추가, 프로메테우스 연동, 파이프라인 이해 
  • Github Actions
  • Travis CI
  • TeamCity
  • Circle CI
  • Bamboo
  • Azure DevOps

 


Learn how to monitor software and Infrastructure

  • Infrastructure Monitoring :  Prometheus, Nagios, Grafana, Zabbix, Monit, Datadog
  • Application Monitoring : Jaeger, New Relic, Instana, AppDynamics, OpenTracing
  • Logs Management : Elastic Search, Graylog, Splunk, Papertrail

 


Cloud Providers

  • AWS 
  • GCP
  • Azure
  • Heroku
  • Digital Ocean
  • Linode
  • Vultr
  • NCP

 


Cloud Design Patterns

  • Availability
  • Data Management
  • Design and Implementation
  • Management and Monitoring

 

728x90
반응형
728x90
반응형

IaC (Infrastructure as Code)

 소프트웨어를 작성하는 것처럼 인프라를 코드로 관리하는 것을  IaC라고 한다.

인프라를 코드로 관리할 때의 장점은 아래와 같다.

  • 효율적인 구성 관리 : IaC로 인프라를 구성할 때의 장점 중 하나는 버전 관리 시스템(Git 등)을 활용할 수 있다는 점이다. 이를 통해 인프라의 구성을 버전별로 추적하고 이전 버전으로 되돌리는 등 인프라 구성을 쉽게 수정할 수 있다.
  • 자동화 : IaC를 사용하면 인프라가 자동으로 구성되기 때문에 사람이 구성할 때보다 신뢰성과 정확성이 증가한다.
  • 쉬운 구축과 배포: IaC를 사용하면 인프라 구축과 배포가 쉽고 빨라진다.
  • 히스토리 : 직접 구축된 서버를 보면 실제로 사용하진 않지만, 작업 중에 남겨진 흔적 등이 발견되는 경우가 있다.
    이럴 때 이력이 없다면 의미를 이해하기 쉽지않다. 하지만 코드를 통해만들어졌다면 코드를 읽어만 봐도 인프라 구성을 한 눈에 알 수 있게 된다.
  • 멱등성 : 언제 어디서 실행해도 동일한 인프라를 구성할 수 있다.

 DevOps 관점에서의 IaC는 개발자와 운영자가 SDLC 상에서 더 가까이 있을 수 있게 하고 운영을 더 명확하게 하며, 운영 업무에 소프트웨어 개발 원칙과 반복성을 적용할 수도 있다. 또한 DevOps의 핵심인 자동화와 협업을 위해서 버전 관리 시스템을 사용하여 IaC를 관리할 경우, 팀으로 하여금 효과적으로 협력하는 방법에 관한 허브 역할도 수행할 수 있다.


IaC의 종류

 코드로 인프라를 다룰 수 있게 도와주는 도구들은 여러가지가 있다.

각 도구마다 IaC의 구현 방식과 특성이 다르고, 인프라의 특성에 따라 사용할 때 이점이 다른 경우도 있다.

  • Chef (2009) : 루비 형태의 DSL(도메인 특화 언어)를 사용하여 recipe(레시피)를 작성한다. 사용을 위해 대상 서버에 별도의 agent 설치가 필요하다.  
  • Puppet (2005) : Chef와 비슷하게 루비로 작성된 DSL를 사용하고, Agent를 설치해야한다. 
  • SaltStack (2011) : ZeroMQ를 사용하여 비동기로 인프라를 구축할 수 있다. Agent가 필요하며 yaml을 사용한다. 
  • Ansible (2012) : agent-less 방식으로 ssh 접속만 가능해도 사용할 수 있다. yaml을 사용하여 코드를 작성할 수 있으며 2015년 Redhat에 인수되었다.
  • Terraform (2014) : Hashicorp에서 제공하는 오픈소스 IaC로 HCL과 JSON을 사용한다. 클라우드 인프라를 코드로 구성할 수 있다.
  • Azure Resource Manager : Microsoft Azure에서 제공하는 IaC 도구로 Azure 자원을 관리할 수 있다.
  • AWS CloudFormation : AWS에서 제공하는 IaC 도구로 AWS 자원을 관리할 수 있다.

위 내용 중 Terraform과 SaltStack, Ansible를 앞으로 블로그에 정리해볼 계획이다.

 

728x90
반응형
728x90
반응형

 

Jenkins

 젠킨스는 오픈소스 CI 툴이다. 원 제작자는 카와구치 코스케이고 JAVA로 제작되었으며 MIT License를 따른다.

원래 목적은 자바 프로젝트의 CI였지만 여기서는 팀에서 제작한 Pluto 프로젝트의 컨테이너를 빌드하고 Docker Hub에 업로드 하여 버전 관리와 컨테이너 배포까지 (반)자동으로 이루어지도록 아래처럼 간단한 CI/CD를 작성해보았다.

 

 


 

Python 프로젝트 컨테이너화 시키기

 먼저 팀 프로젝트의 결과물인 Pluto(Flask 웹 서버)를 자동 배포하기 위해 서버를 컨테이너화 시켰다.

컨테이너화가 어렵게 느껴질 수 있지만 내가 했던건 이미 만들어진 우분투 컨테이너에 필요한 조치를 하고 서버를 올리는 스크립트(?)를 작성한게 전부다.

 

 아래는 파이썬 프로젝트를 Ubuntu:20.04 컨테이너에 넣고 실행시켜주는 Dockerfile 이다.

FROM ubuntu:20.04
MAINTAINER hwan001 "MyGoogleAccount@gmail.com"

RUN apt-get update
RUN apt-get install -y vim net-tools
RUN apt-get install -y python3-dev build-essential python3 python3-pip python3-venv

COPY . /Pluto
WORKDIR /Pluto

RUN pip install -r requirements.txt
RUN rm -rf ./docker_*.ps

ENTRYPOINT ["python"]
CMD ["run.py"]

 

dockerfile을 실행하면 공식 우분투 컨테이너 이미지를 다운로드 받아와 apt install, 작업 디렉토리 생성 후 소스코드 복사하고 서버를 실행한다.

 

프로젝트에서 사용하는 DockerFile은 프로젝트 폴더에 같이 포함되어 있으며, 위의 파일을 조금 수정해서 사용한다. 


 

젠킨스 설정 및 스크립트 작성

 아래 과정들은 설치해둔 Remote 빌드 서버와 젠킨스 서버에서 작성해주었다. Remote 빌드 서버(노드)를 만들고 연결하는 과정은 생략한다.

 

GitHub와 연동

 Item을 생성하고 GitHub와 연동하여 코드를 가져오는 부분은 아래 사진처럼 해두었다. 해당 Item이 빌드되면 자동으로 코드를 가져온다.

**Failed 뜨지만 됨, 이유는 확인 중

 

Execute Shell

워크스페이스로 이동해서 스크립트들을 실행하고 해당 공간을 삭제하는 코드이다.

docker_build, docker_push 등은 도커 명령어를 좀더 간단하게 다루기 위해 추가한 쉘 스크립트 파일들이다.

개발하면서 버전을 올려 배포하고 싶을 때 properties.sh 에서 버전만 변경하고 GitHub에 Push해준 뒤 젠킨스로 빌드해주면 된다. docker_run.sh는 서버를 직접 실행할 때 사용하는 코드이다. (아래 코드들 참고)

cd ${WORKSPACE}
bash docker_build.sh
bash docker_push.sh
rm -rf ${WORKSPACE}

 

properties.sh

#!/bin/bash
version=0.0.5
imagename=hwan001/pluto

 

docker_build.sh

#!/bin/bash
source ./properties.sh

docker build -t ${imagename}:${version} .

 

docker_push.sh

#!/bin/bash
source ./properties.sh

docker push ${imagename}:${version}
docker push ${imagename}:latest

 


 

Docker Hub에 배포하고 서버에 설치하기

 Docker Hub에 이미지를 배포하기 위해 설정하는 과정을 생략했다. 아래 이미지를 다운받아 실행하면 docker로 실행하면바로 flask 웹 서버가 올라가는 걸 볼 수 있다. 

 

 서버는 Docker Hub에 Public으로 배포해 두었기 때문에 누구나 다운로드 받아볼 수 있다. (참고로 서버는 미완성이고 계속 변경될 수 있다.)

 

docker_run.sh

#!/bin/bash
source ./properties.sh

docker run -it --network=host ${imagename}:${version}

간단하게 실행해보려면 도커가 설치된 서버에서  Docker_run.sh 파일을 bash로 실행하면 된다.

 

만약 필요한 사람들만 다운로드 할 수 있게 하려면 GitHub처럼 Private로 배포하고 Collaborators에 계정을 추가해주면 된다. 하지만 이 기능은 유료기 때문에 다른 대안이 필요하다. 

 

나중에 기회가 된다면 해당 내용과 관련해서 글을 정리해보겠다.

 

728x90
반응형

'DevOps > CICD' 카테고리의 다른 글

Jenkins에 설치된 플러그인 목록 얻기  (0) 2023.08.10
728x90
반응형

 

AWS 프리티어 가입

 

AWS 프리티어는 1년간 무료로 제공되는 EC2 인스턴스이다.

회원 가입 이후에 사용이 가능하며, 가입 시 신용카드 정보를 등록하기 때문에 1년이 지난 이후에는 자동으로 비용이 청구된다.

 

먼저 회원가입을 위해 아래 이미지의 내용을 영어로 채워주자. 

 

입력을 마치고 진행하게되면 핸드폰 인증과 서포트 플랜 선택을 하게된다.

서포트 플랜은 기본 지원, 개발자 지원, 비즈니스 지원이 있으며 기본 지원을 제외한 나머지는 금액이 부과된다.

기본 지원을 선택해주자.

 


 

설정

가입이 완료되었다면 기본적으로 설정해줄 내용들이 있다.

가장 먼저 오른쪽 상단의 도시명을 클릭해서 서울로 바꿔준다. 

 

지역 설정이 끝났다면, 사용량과 결제에 대한 알림을 설정해보자.

우측 상단의 계정명을 클릭하고 결제 대시보드로 이동해준다.

 

기본 설정 > 결제 기본 설정 탭의 프리 티어 사용량 알림 받기결제 알림 받기 항목을 체크하고 사용량 알림을 받을 이메일 주소를 입력한 뒤 저장해준다.

 

결제 알림 받기는 설정해둔 조건에 맞는 결제에 대해 SNS를 보내준다. 하지만 설정을 위해서는 AWS CloudWatch 서비스에 결제 경보를 생성해 줘야 한다. 결제 알림 받기 항목 설명란의 결제 알림 관리를 눌러 서비스로 이동해주자.

 

Cloud Watch 서비스를 통해 결제 알림을 받기 위해서는 우선 리전을 버지니아 북부로 설정해주어야 한다.

서울로 설정 시의 카테고리와 버지니아 북부 설정 시의 카테고리가 다르다.

좌측 서울, 우측 버지니아

 

리전을 설정해 주었다면 좌측의 경보 > 결제 탭을 눌러 경보 생성 버튼을 눌러준다.

경보 생성 버튼을 누르면 4단계의 작업을 진행해야 한다.

 

지표 선택을 누른다.

 

아래 화면에서 결제 > 예상 요금 합계 > USD 를 체크하고  지표 선택 버튼을 눌러준다.

 

조건을 설정해준다. 5달러 이상 비용이 발생하면 알림이 발생하게 설정해주었다.

 

새 주제 생성을 눌러 이메일을 입력하고 다음을 눌러 설명을 작성해준다.

 

설정이 완료되면 비용 발생 경보가 생성되었다.

 


 

MFA 등록

AWS에서 지원해주는 MFA(Multi Factor Authentication)는 다요소 인증으로 일종의 OTP를 여러 방식으로 지원한다고 생각하면 편하다. 이 글에서는 가상 MFA 디바이스인 Authy 어플을 사용하여 MFA를 생성한다.

계정의 해킹 방지하기 위해 비밀번호 인증과 추가 보안 조치를 설정해주자.

 

우측 상단의 계정명을 눌러 보안 자격 증명을 클릭한다.

 

멀티 팩터 인증을 선택하고 MFA 활성화 버튼을 누르면, MFA 디바이스 관리 창이 뜬다.

 

가상 MFA 디바이스를 선택하고 계속을 누르면 QR 코드를 만들어주는 창이 나온다.

설치된 어플을 사용해서 QR코드를 촬영해주고 해당 어플에서 30초 간격으로 갱신되는 코드를 2번 입력해준다.

 

이제부턴 로그인 시 해당 어플을 통한 MFA 인증 과정이 필요하다. 

적용 여부의 확인은 로그아웃 후 재 로그인해보면 알 수 있다.

 

728x90
반응형

'DevOps > AWS' 카테고리의 다른 글

2023년 AWS 서비스 종류 별 기능 요약  (2) 2023.03.28
728x90
반응형

글 목적

아래 내용은 docker 설치와 이미지를 run한 이후 내부 컨테이너에서 apt-get update하는 부분부터 에러가 발생하여 해결하기 위해 삽질한 과정이다.

환경을 설치하고 Django web 페이지를 띄울 때까지 오류 상황들을 순서대로 적은 글이고 중간에 돌아가는 과정이 있기 때문에 빠른 결론을 원하면 아래 apt-get update 성공 부분부터 읽으면 될 듯 하다.

만약 이 글과 비슷한 상황이라면 순서대로 읽는 것 보단 필요한 부분만 찾아서 시도해보길 바란다. 

 

도커 이미지는 아래 명령어로 run하였고, 컨테이너 이름은 test이다.

$ sudo docker run -it --name=test ubuntu:20.04 /bin/bash

 

docker 설치나 사용에 관한 내용은 아래 링크 참조.

https://hwan001.tistory.com/180

 

[Docker] Ubuntu에 Docker 설치하기

Docker ? 리눅스 컨테이너화 기술로 사용자가 리눅스 컨테이너를 만들고 사용할 수 있도록 지원한다. 도커는 가상화 기술이 아닌 격리 기술이지만 가상 머신과 비슷한 느낌으로 사용한다. 컨테이

hwan001.co.kr


 

apt-get update 에러

 Ubuntu:20.04 컨테이너를 실행하고 가장 먼저 apt-get update 명령어를 사용했지만, Err 메시지가 뜨면서 모든 저장소에 연결되지 않았다. 또한 ip, vi, ping, route 등의 기본 명령어들도 제공되지 않아 원인 파악도 제한된다.

검색해보니 docker의 보안으로 인해 최초에 해당 기능들이 제공되지 않기 때문에 만약 필요하면 apt-get install로 각각을 설치해서 사용하라고 하는데, 문제는 apt-get 저장소 연결 자체가 안되는 상황이다. 

 

원인을 검색해봤더니 DNS 연결 문제로 저장소 URL을 찾을 수 없어 발생하는 에러기 때문에 해당 주소를 잘 변경해주면 연결이 된다고 한다. DNS 주소를 수정하는 방법은 아래 링크를 참고했다.

https://askubuntu.com/questions/1167080/unable-to-update-ubuntu-docker-container-using-apt-get-update

 

unable to update ubuntu Docker container using apt-get update

when I run ubuntu as Docker container and when I run apt-get update command it gives error and fails to update the repos. Here is what error I'm getting : root@df167e514b29:/# sudo bash: sudo: c...

askubuntu.com

검색을 통해 /etc/resolv.conf 등 필요한 파일들을 수정해줬고, DNS (8.8.8.8) 주소도 잘 설정되어 있다.

하지만 여전히 update가 안되었기 때문에 결국 필요한 패키지들을 수동으로 설치하기로 했다.


 

apt-get download

보통 필요한 패키지들은 apt-get install로 시스템에 바로 설치하지만 현재는 원인을 알 수 없는 이유로 저장소 연결이 제한된다. 패키지의 수동 설치를 위해서 먼저 docker 컨테이너를 빠져나가 apt-get이 잘 작동되는 os에서 필요한 패키지들을 다운로드 받는다.

 

$ sudo apt-get download vim net-tools iproute2 iputil-ping

 

apt-get download 명령어는 현재 디렉토리에 .deb 형태로 필요한 패키지를 다운로드 받는다.

aaa라는 임시 폴더를 만들어 내부에 필요한 deb 들을 설치했다.

 

이제 이 파일들을 도커 내부의 ubuntu:20.04로 전달하여 수동으로 설치하면 된다.


 

docker cp

도커는 도커 외부와 내부 컨테이너 간의 파일 공유가 가능하며 docker cp 명령어로 해당 기능을 제공한다.

위에서 내려받은 deb 파일을 ubuntu:20.04 컨테이너에 넣어준다.

$ sudo docker cp ../aaa/ test:/aaa/

잘 전달되었다.

이제 전달된 deb를 설치해주자.


 

apt install ./

apt install 명령어를 사용하면 패키지를 설치할 수 있다.

여기서 주의할 점이 있는데, install 뒤에 패키지 명을 그냥 입력하면 저장소에서 해당 패키지를 찾기 때문에

./을 붙여 현재 디렉토리 내부의 파일이라고 명시해 주어야 한다.

 

하나씩 설치해보겠다.

$ apt install ./net-tools_1.60+git20180626.aebd88e-1ubuntu1_amd64.deb

net-tools

 

$ apt install ./iputils-ping_3%3a20190709-3_amd64.deb

iputils-ping 에러

 

iputil-ping 패키지를 설치하던 중 의존성과 관련된 에러가 발생했다.

libcap2 와 libcap2-bin이 설치되지 않아 발생한 에러이다.

docker 외부에서 다운받은 뒤 같이 설치해주자.

$ apt-get download libcap2 libcap2-bin

 

설치할땐 libcap2-bin의 의존성 때문에 libcap2를 먼저 설치해줘야 한다. 

 

iputils-ping을 설치해보자.

 

드디어 iputils-ping의 설치가 끝났다.

다른 패키지들도 비슷한 방식으로 설치하면 되지만 사실 중요한건 패키지 설치가 아니라 환경 구축이다.

더 이상 설치하지 말고 ping을 사용해서 저장소와 연결 상태를 먼저 확인해보자.


 

Ping

DNS로 먼저 날려봤지만 당연하다는 듯 패킷이 나가지 않는다.

 

게이트 웨이로도 연결이 안된다..

 

여기서 추론 가능한 연결 실패 원인은 크게 2가지인 것 같다.

방화벽에서 패킷이 drop 당하거나, 이중 NAT로 인한 route 문제.

 

방화벽은 없으니 홈 서버를 구성하면서 뭔가 문제가 생긴 듯 하다.


 

docker network

좀 더 찾아보니 도커는 docker network 명령어로 네트워크 생성, 설정 등의 작업을 지원한다.

원래 해당 명령어는 컨테이너들 간의 통신을 가상 네트워크 장비를 통해 지원해주는게 주 역할이지만 내 문제해결에도 큰 도움이 됐다. 

이 글에서 한번에 작성하기엔 범위가 크고 주제도 맞지 않기 때문에 명령어 설명은 생략하겠다.

 

기본적으로 컨테이너를 생성하면 브릿지 형태의 네트워크로 설정된다. 

컨테이너 밖에서 ifconfig 해보면 docker0라는 가상 네트워크 인터페이스가 생긴걸 알 수 있다.

컨테이너 외부의 가상 인터페이스 ip는 D클래스가 1번으로 지정되어 있고, 내부에서 ifconfig 설치 후 확인해보면

172.17.0.2를 갖는걸 볼 수 있다.

 

위에선 생략했지만 ping으로 컨테이너 내부에서 172.17.0.1 주소에 패킷을 날려보면 응답이 온다.

 

문제가 거의 해결된 것 같다. 정확하진 않지만 NAT 환경과 관련된 문제인것 같다.

해결 방법은 여러가지가 있겠지만, 제일 간단한 해결 방법은 컨테이너를 브릿지가 아닌 호스트 방식으로 run하는 것이다.

 

기존에 만든 test 이미지를 과감하게 지우고 host 네트워크로 다시 만들어보겠다.


 

apt-get update 성공

아래 명령어로 test를 삭제하고 네트워크를 host로 지정해서 다시 만들어보자.

$ sudo docker rm test
$ sudo docker run -it --name=test --network=host ubuntu:20.04 /bin/bash

 

쉘이 바뀌었는데 기존처럼 랜덤한 컨테이너 ID가 아니라 host와 같은 내용의 root 쉘이 되었다.

이제 업데이트를 해보자.

$ apt-get update

 

업데이트가 잘 된다. 추가로 필요한 패키지는 apt-get install로 설치하면 될 듯 하다.

해결 방법은 docker run할때 --network=host 라는 옵션을 하나 추가한 것 밖에 없지만 과정은 생각보다 길었던 것 같다.

 

이제 만들어진 ubuntu:20.04 컨테이너에 파이썬과 Django 프레임워크를 설치해서 간단한 웹사이트를 띄워보자.


 

Django 

설치 과정은 https://hwan001.tistory.com/186 글과 같지만 몇 가지 명령어가 다른 점이 있다.

달라진 명령어는 아래 내용에 적어두었다.

 

먼저 apt repository를 국내에서 제공하는 서버로 바꿔주자.

이 글에선 컨테이너 외부의 우분투에 미리 설정되어 있기 때문에 해당 파일을 도커 내부 같은 경로에 cp 명령어로 덮어씌워 줬다.

아래는 /etc/apt/source.list의 내용이고 기존 파일에 kakao 서버 주소만 추가해 주었다.

필요하다면 그대로 사용해도 좋고 다른 국내 서버 주소를 찾아서 추가해줘도 좋다.

 

$ vi /etc/apt/source.list
# deb cdrom:[Ubuntu 20.04.4 LTS _Focal Fossa_ - Release amd64 (20220223)]/ focal main restricted

# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
# newer versions of the distribution.
deb http://kr.archive.ubuntu.com/ubuntu/ focal main restricted
# deb-src http://kr.archive.ubuntu.com/ubuntu/ focal main restricted


## Major bug fix updates produced after the final release of the
## distribution.
deb http://kr.archive.ubuntu.com/ubuntu/ focal-updates main restricted
# deb-src http://kr.archive.ubuntu.com/ubuntu/ focal-updates main restricted

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team. Also, please note that software in universe WILL NOT receive any
## review or updates from the Ubuntu security team.
deb http://kr.archive.ubuntu.com/ubuntu/ focal universe
# deb-src http://kr.archive.ubuntu.com/ubuntu/ focal universe
deb http://kr.archive.ubuntu.com/ubuntu/ focal-updates universe
# deb-src http://kr.archive.ubuntu.com/ubuntu/ focal-updates universe

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team, and may not be under a free licence. Please satisfy yourself as to
## your rights to use the software. Also, please note that software in
## multiverse WILL NOT receive any review or updates from the Ubuntu
## security team.
deb http://kr.archive.ubuntu.com/ubuntu/ focal multiverse
# deb-src http://kr.archive.ubuntu.com/ubuntu/ focal multiverse
deb http://kr.archive.ubuntu.com/ubuntu/ focal-updates multiverse
# deb-src http://kr.archive.ubuntu.com/ubuntu/ focal-updates multiverse

## N.B. software from this repository may not have been tested as
## extensively as that contained in the main release, although it includes
## newer versions of some applications which may provide useful features.
## Also, please note that software in backports WILL NOT receive any review
## or updates from the Ubuntu security team.
deb http://kr.archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse
# deb-src http://kr.archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse

## Uncomment the following two lines to add software from Canonical's
## 'partner' repository.
## This software is not part of Ubuntu, but is offered by Canonical and the
## respective vendors as a service to Ubuntu users.
# deb http://archive.canonical.com/ubuntu focal partner
# deb-src http://archive.canonical.com/ubuntu focal partner

deb http://security.ubuntu.com/ubuntu focal-security main restricted
# deb-src http://security.ubuntu.com/ubuntu focal-security main restricted
deb http://security.ubuntu.com/ubuntu focal-security universe
# deb-src http://security.ubuntu.com/ubuntu focal-security universe
deb http://security.ubuntu.com/ubuntu focal-security multiverse
# deb-src http://security.ubuntu.com/ubuntu focal-security multiverse

# This system was installed using small removable media
# (e.g. netinst, live or single CD). The matching "deb cdrom"
# entries were disabled at the end of the installation process.
# For information about how to configure apt package sources,
# see the sources.list(5) manual.


# kakao
deb http://ftp.daumkakao.com/ubuntu/ bionic main restricted
deb http://ftp.daumkakao.com/ubuntu/ bionic-updates main restricted
deb http://ftp.daumkakao.com/ubuntu/ bionic universe
deb http://ftp.daumkakao.com/ubuntu/ bionic-updates universe
deb http://ftp.daumkakao.com/ubuntu/ bionic multiverse
deb http://ftp.daumkakao.com/ubuntu/ bionic-updates multiverse
deb http://ftp.daumkakao.com/ubuntu/ bionic-backorts main restricted universe multiverse

 

파일을 덮어씌우고 update와 upgrade를 한번씩 더 해줬다.

 

이제 python3, pip3, vim, venv를 apt-get install로 설치한다.

$ apt-get install -y python3 python3-pip python3-venv vim

 

이후 과정은 위 링크와 동일하다.

 

 

 

728x90
반응형
728x90
반응형

 

Docker Hub 와 Docker Repository

 도커는 깃 허브와 비슷한 구조로 만들어졌다.

사용자들은 여러 명령어를 활용해 Docker를 설치하고 이미지를 내려받아 필요한 환경을 구축한 후 이미지를 다시 빌드하여 허브에 업로드할 수 있고, 업로드된 이미지는 (인터넷이 가능하고 Docker가 설치되었다면) 언제든 다시 내려받아 사용할 수 있게된다. 

 

 이런 과정들을 가능하게 하려면 먼저 Docker Hub에 계정을 만들고, 이미지를 배포하고 관리할 Repository를 생성해야 한다. Repository의 이름은 배포할 이미지의 이름과 같아야 한다. (태그는 보통 버전관리를 위해 사용)

 

 아래 링크에서 가입이 가능하다. 

 https://hub.docker.com/

 

Docker Hub Container Image Library | App Containerization

We and third parties use cookies or similar technologies ("Cookies") as described below to collect and process personal data, such as your IP address or browser information. You can learn more about how this site uses Cookies by reading our privacy policy

hub.docker.com


 

Docker Commit

 도커 허브에 만들어둔 Repository에 이미지를 업로드하려면, 먼저 이미지를 만들어야한다.

아래 명령어에서 -a 옵션은 commit할 이미지의 작성자명이고, -m 옵션은 주석이다.

commit 하고 싶은 이미지의 Container ID를 docker image로 확인하고 이미지네임과 태그를 추가로 입력해준다.

이 때 이미지네임과 태그는 도커 허브에 만들어둔 레포지토리 명과 동일해야한다.

혹시 다르게 생성했다면 아래 Tag 명령어를 사용해 commit 전에 변경이 가능하다.

 

$ sudo docker commit -a "hwan001" -m "commit message" 컨테이너id 이미지네임/태그

 

Docker Tag

 도커 저장소에 이미지를 push 하려면 도커의 저장소 이름과 이미지가 서로 같은 이름을 가지고 있어야 한다.

위에서 만들어진 이미지의 이름과 tag를 아래 명령어로 변경해주자.

$ sudo docker tag 원래이름:태그 hwan001/django_webserver_test:0.1

 

Docker Push

 태그까지 맞췄다면 아래 명령어로 허브에 업로드 할 수 있다.

$ sudo docker push hwan001/django_webserver_test:0.1

 

업로드 확인

허브의 레포지토리에 잘 업로드 되었다.

728x90
반응형
728x90
반응형

Docker

이전 글 : Ubuntu에 Docker 설치하기 (1)

https://hwan001.tistory.com/180

 

[서버] Ubuntu에 Docker 설치하기

Docker ? 리눅스 컨테이너화 기술로 사용자가 리눅스 컨테이너를 만들고 사용할 수 있도록 지원한다. 도커는 가상화 기술이 아닌 격리 기술이지만 가상 머신과 비슷한 느낌으로 사용한다. 컨테이

hwan001.tistory.com


Docker에서 Ubuntu 20.04 LTS 최신 버전 공식 이미지 내려받기

 Docker를 설치하면 도커 허브에 공유된 공식 이미지 또는 개인이 업로드한 이미지와 직접 제작한 이미지 등을 다운로드하여 원하는 환경을 쉽게 구성할 수 있다.

 

먼저 아래 명령어를 사용하면 도커 허브에 공유되고 있는 이미지 목록을 가져온다.

$ sudo docker search {image_name}

 

아래 명령어는 이미지를 도커 허브로부터 다운로드 받는다.

태그를 통해 해당 이미지의 특정 버전을 다운받아오거나 :latest 태그를 활용하여 최신 버전 이미지를 받아올 수 있다.

$ sudo docker pull ubuntu:latest

 

이미지를 내려받은 후 실행 까지 하려면 docker run 명령어를 실행하면 된다.

$ sudo docker run -i -t ubuntu:20.04 /bin/bash

이미지를 내려받은 뒤 컨테이너에 접속하여 bash 쉘을 실행 시켰다.

참고로 이미지가 있는 상태에서 run하게 되면 새로운 컨테이너가 생긴다.


컨테이너 접속

Exit 후 아래 명령어로 확인해보면 이미지의 빨간색 박스 부분처럼 도커가 임의로 컨테이너의 이름을 정해준 것을 알 수 있다.

$ sudo docker ps -a

 

docker start 명령어로 도커가 임의로 정한 컨테이너의 이름을 입력하고,

docker ps를 입력하면 현재 도커 내부에서 실행 중인 이미지가 보이지만 쉘의 형태는 변하지 않는다.

해당 컨테이너는 정상적으로 실행되었지만 아직 내부로 들어가진 않았다.

$ sudo docker start hungry_williamson
$ docker ps

 

컨테이너에 접속하여 쉘을 실행하기 위해선 추가적인 과정이 필요하다.

$ sudo docker attach hungry_williamson

 

docker attach 명령어로 실행 중인 컨테이너에 접속했다.


이미지, 컨테이너 삭제

만약 이미지와 컨테이너를 삭제하고 싶다면 아래 명령어를 사용한다.

$ sudo docker rm {컨테이너 이름}

$ sudo docker rmi ubuntu

 

728x90
반응형
728x90
반응형

Docker

 

Docker

  • 리눅스 컨테이너화 기술로 사용자가 리눅스 컨테이너를 만들고 사용할 수 있도록 지원한다.
  • 도커는 가상화 기술이 아닌 격리 기술이지만 가상 머신과 비슷한 느낌으로 사용한다.
  • 컨테이너를 구축, 배포, 복사하며 환경의 이전이 자유롭기 때문에 AWS 등 클라우드 서비스에 최적화되었다.
  • 처음엔 리눅스의 LXC 기술(기존의 컨테이너)을 활용하였으나 현재는 자체 개발된 기술 활용한다.
  • 도커는 단일 컨테이너 관리에 적합하게 만들어져 있다. (다수의 컨테이너를 다루려면 쿠버네티스 활용)
  • https://www.docker.com/
 

Home - Docker

A Community like No Other Community is at the heart of what Docker does. From our Docker Captains sharing their insight and expertise, to hundreds of MeetUps around the world, to our Slack and Discourse forums for peer-to-peer support, there’s someone el

www.docker.com


 

Docker 설치

 도커는 실제 Linux 서버에 설치 후 공식 매뉴얼 (https://docs.docker.com/engine/install/ubuntu/) 을 참고하여 작성했고, 다른 운영체제에서의 설치가 필요하다면 공식 매뉴얼을 참고하기 바란다.

아래 내용은 Ubuntu 20.04 LTS 기반이며, 서버는 미리 설치 후 설정까지 되어 있다고 가정하고 진행하겠다.

 

** 서버 OS 요구사항이 존재함 설치 전 참고

도커 설치를 위한 서버 요구사항

 

 

서버가 준비되었다면 도커 설치를 위해 가장 먼저 OS에 존재하는 이전 버전 docker (docker, docker.io, docker-engine)를 제거해야되고, 아래 명령어를 통해 제거가 가능하다.

$ sudo apt-get remove docker docker-engine docker.io containerd runc

 

 

제거가 완료되었다면 apt-get를 업데이트하고 curl과 기타 패키지를 설치한다.

 $ sudo apt-get update
 $ sudo apt-get install ca-certificates curl gnupg lsb-release

 

 

이후 curl로 도커의 공식적인 gpg 키를 가져온 뒤 gpg 명령어로 추가한다.

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

 

 

위에서 가져온 키를 사용하여 도커 이미지를 다운받아올 deb 명령어 만들어 /etc/apt/sources.list.d/docker.list 에 추가한 뒤 결과를 출력해준다.

 $ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg]\
 https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"\
 | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

$(dpkg --print-architecture) 는 현재 서버의 아키텍쳐를 가져오고, $(lsb_release -cs) stable은 우분투 배포판의 버전을 가져온다. 여기서 stable은 docker 이미지의 버전으로 nightly 또는 test 입력이 가능하다.

 

관련 내용은 아래 링크 내용의 nightly와 test 항목 참조.

https://docs.docker.com/engine/install/

 

Install Docker Engine

 

docs.docker.com

 

명령어 실행 후 vi로 /etc/apt/sources.list.d/docker.list 파일을 열어보면 출력된 결과가 파일 내에 작성되어진 걸 볼 수 있다.

 

 

아래 명령어로 도커 엔진의 가장 최신 버전과 index 패키지를 다운로드한다.

$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

 

** 도커 엔진의 특정 버전이 필요하다면 아래 이미지 또는 공식 매뉴얼 참조

다른 버전 설치 방법

 

 

도커의 다운로드와 설치가 끝났다.

아래 명령어로 기본 도커와 같이 설치되는 Hello-world 이미지를 run 한다.

$ sudo docker run hello-world


 

 

728x90
반응형

+ Recent posts