자동화
Automation
수동 작업을 자동으로 수행하게 만드는 것. 인프라, 배포, 테스트 자동화. DevOps의 핵심.
Automation
수동 작업을 자동으로 수행하게 만드는 것. 인프라, 배포, 테스트 자동화. DevOps의 핵심.
자동화(Automation)는 사람이 수동으로 수행하던 반복적인 작업을 스크립트, 도구, 또는 시스템을 통해 자동으로 실행되게 만드는 것입니다. IT 분야에서 자동화는 인프라 프로비저닝, 코드 빌드/테스트/배포, 모니터링 및 경보, 보안 점검 등 거의 모든 영역에 적용됩니다. 자동화의 핵심 목표는 인적 오류 감소, 작업 속도 향상, 일관성 확보, 그리고 엔지니어가 창의적인 업무에 집중할 수 있게 하는 것입니다.
인프라 자동화(Infrastructure as Code, IaC)는 서버, 네트워크, 스토리지 등 인프라를 코드로 정의하고 자동으로 프로비저닝하는 방식입니다. Terraform, Pulumi, AWS CloudFormation 등의 도구를 사용하면 수백 대의 서버를 몇 분 만에 동일한 구성으로 생성할 수 있습니다. 인프라 코드는 버전 관리되므로 변경 이력 추적, 롤백, 코드 리뷰가 가능하며, 개발/스테이징/프로덕션 환경 간 일관성을 보장합니다.
CI/CD(Continuous Integration/Continuous Deployment)는 소프트웨어 개발 자동화의 핵심입니다. 개발자가 코드를 커밋하면 자동으로 빌드, 단위 테스트, 통합 테스트, 코드 품질 검사가 실행되고(CI), 검증된 코드는 자동으로 스테이징이나 프로덕션 환경에 배포됩니다(CD). GitHub Actions, GitLab CI, Jenkins, CircleCI 등의 도구가 널리 사용됩니다. 테스트 자동화는 특히 중요한데, 변경이 기존 기능을 손상시키지 않는지(회귀 테스트) 사람의 개입 없이 확인할 수 있습니다.
운영 자동화는 시스템 모니터링, 로그 분석, 경보 발생, 인시던트 대응까지 포함합니다. 예를 들어, 서버 CPU 사용률이 90%를 초과하면 자동으로 인스턴스를 추가(Auto Scaling)하거나, 보안 이상 징후가 감지되면 자동으로 IP를 차단하고 담당자에게 알림을 보낼 수 있습니다. Ansible, Chef, Puppet 등의 구성 관리 도구는 수천 대의 서버에 동일한 설정을 일괄 적용하고 드리프트(설정 불일치)를 감지합니다. MLOps에서는 모델 학습, 평가, 배포, 재학습까지 자동화하여 AI 시스템의 지속적인 개선을 가능케 합니다.
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
NODE_VERSION: '20'
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# 1. 코드 품질 검사 (병렬 실행)
lint-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run type check
run: npm run type-check
- name: Run unit tests
run: npm test -- --coverage
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
# 2. 보안 스캔
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
severity: 'CRITICAL,HIGH'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
# 3. Docker 이미지 빌드 및 푸시
build-and-push:
needs: [lint-and-test, security-scan]
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=
type=raw,value=latest
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
# 4. 스테이징 환경 배포
deploy-staging:
needs: build-and-push
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v4
- name: Deploy to Kubernetes (Staging)
uses: azure/k8s-deploy@v4
with:
manifests: k8s/staging/
images: ${{ needs.build-and-push.outputs.image-tag }}
namespace: staging
- name: Run smoke tests
run: |
sleep 30 # 배포 안정화 대기
curl -f https://staging.example.com/health || exit 1
# 5. 프로덕션 배포 (수동 승인 필요)
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production # 승인 필요 설정
steps:
- uses: actions/checkout@v4
- name: Deploy to Kubernetes (Production)
uses: azure/k8s-deploy@v5
with:
manifests: k8s/production/
images: ${{ needs.build-and-push.outputs.image-tag }}
namespace: production
strategy: canary
percentage: 20
- name: Monitor canary deployment
run: |
# 카나리 배포 모니터링 (에러율 체크)
./scripts/monitor-canary.sh --threshold 1%
# main.tf - AWS 인프라 자동 프로비저닝
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
# 상태 파일 원격 저장 (팀 협업)
backend "s3" {
bucket = "my-terraform-state"
key = "production/terraform.tfstate"
region = "ap-northeast-2"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = var.environment
ManagedBy = "Terraform"
Project = var.project_name
}
}
}
# 변수 정의
variable "environment" {
description = "배포 환경 (staging, production)"
type = string
}
variable "aws_region" {
default = "ap-northeast-2"
}
variable "project_name" {
default = "my-app"
}
# VPC 및 네트워크 (모듈 사용)
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "${var.project_name}-vpc"
cidr = "10.0.0.0/16"
azs = ["${var.aws_region}a", "${var.aws_region}b", "${var.aws_region}c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
single_nat_gateway = var.environment == "staging" ? true : false
enable_dns_hostnames = true
enable_dns_support = true
}
# EKS 클러스터
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 19.0"
cluster_name = "${var.project_name}-${var.environment}"
cluster_version = "1.28"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
eks_managed_node_groups = {
main = {
min_size = var.environment == "production" ? 3 : 1
max_size = var.environment == "production" ? 10 : 3
desired_size = var.environment == "production" ? 3 : 1
instance_types = ["t3.medium"]
labels = {
Environment = var.environment
}
}
}
# 클러스터 오토스케일링 활성화
cluster_addons = {
coredns = { most_recent = true }
kube-proxy = { most_recent = true }
vpc-cni = { most_recent = true }
}
}
# RDS (PostgreSQL)
module "rds" {
source = "terraform-aws-modules/rds/aws"
version = "~> 6.0"
identifier = "${var.project_name}-${var.environment}"
engine = "postgres"
engine_version = "15"
family = "postgres15"
major_engine_version = "15"
instance_class = var.environment == "production" ? "db.r6g.large" : "db.t3.micro"
allocated_storage = 20
max_allocated_storage = 100
db_name = "myapp"
username = "admin"
port = 5432
multi_az = var.environment == "production"
db_subnet_group_name = module.vpc.database_subnet_group_name
vpc_security_group_ids = [aws_security_group.rds.id]
backup_retention_period = var.environment == "production" ? 7 : 1
deletion_protection = var.environment == "production"
}
# 출력
output "eks_cluster_endpoint" {
value = module.eks.cluster_endpoint
}
output "rds_endpoint" {
value = module.rds.db_instance_endpoint
sensitive = true
}
# playbooks/setup-webserver.yml
---
- name: 웹 서버 구성 자동화
hosts: webservers
become: yes
vars:
app_user: appuser
app_dir: /opt/myapp
nginx_version: "1.24"
tasks:
- name: 시스템 패키지 업데이트
apt:
update_cache: yes
upgrade: safe
when: ansible_os_family == "Debian"
- name: 필수 패키지 설치
apt:
name:
- nginx
- python3-pip
- certbot
- python3-certbot-nginx
- fail2ban
state: present
- name: 애플리케이션 사용자 생성
user:
name: "{{ app_user }}"
shell: /bin/bash
home: "{{ app_dir }}"
create_home: yes
- name: Nginx 설정 파일 배포
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/sites-available/myapp
validate: 'nginx -t -c /etc/nginx/nginx.conf'
notify: Reload Nginx
- name: 사이트 활성화
file:
src: /etc/nginx/sites-available/myapp
dest: /etc/nginx/sites-enabled/myapp
state: link
notify: Reload Nginx
- name: 방화벽 규칙 설정
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop:
- "22"
- "80"
- "443"
- name: Fail2ban 설정
template:
src: templates/jail.local.j2
dest: /etc/fail2ban/jail.local
notify: Restart Fail2ban
- name: 로그 로테이션 설정
template:
src: templates/logrotate.conf.j2
dest: /etc/logrotate.d/myapp
handlers:
- name: Reload Nginx
service:
name: nginx
state: reloaded
- name: Restart Fail2ban
service:
name: fail2ban
state: restarted
# inventory/production.yml
---
all:
children:
webservers:
hosts:
web1:
ansible_host: 10.0.1.10
web2:
ansible_host: 10.0.1.11
web3:
ansible_host: 10.0.1.12
vars:
ansible_user: deploy
ansible_python_interpreter: /usr/bin/python3