본문 바로가기
IT/Cloud

[Cloud] Ansible로 멀티 클라우드 인프라 자동화: AWS, Azure, GCP 통합 관리 가이드

by 수누다 2026. 5. 16.

Ansible로 멀티 클라우드 인프라 자동화: AWS, Azure, GCP 통합 관리 가이드

안녕하세요, 13년차 서버실 지킴이입니다. 요즘 인프라 환경을 보면 단순히 한 클라우드에만 갇혀 있지 않죠? 멀티 클라우드(Multi-Cloud)는 이제 선택이 아니라 필수가 되어가는 시대인 것 같습니다. 저도 처음엔 AWS만 주력으로 썼었는데, 프로젝트가 커지고 요구사항이 다양해지면서 Azure나 GCP도 함께 다루게 되더라고요. 근데 이게 여러 클라우드를 동시에 관리하려니 여간 복잡한 게 아니었습니다. 각 클라우드마다 CLI도 다르고, API도 다르고… 수동으로 관리하다가는 퇴근은커녕 야근만 늘겠다 싶었죠. 😭

이런 고민을 하던 중에 저의 든든한 동반자, Ansible(앤서블)을 떠올렸습니다. Ansible은 이미 온프레미스 환경에서 서버 자동화에 요긴하게 써왔던 도구거든요. '이걸로 멀티 클라우드도 통합 관리할 수 있지 않을까?' 하는 생각에 홈랩에서 이것저것 실험해봤습니다. 결과는 대만족이었습니다! 오늘은 제가 직접 경험하며 삽질했던 내용과 함께, Ansible로 AWS, Azure, GCP 인프라를 한 번에 자동화하는 방법을 여러분께 알려드리려고 합니다. 이 글을 통해 멀티 클라우드 관리의 복잡성을 확 줄여보시길 바랍니다. 자, 그럼 시작해볼까요? 🎉

Ansible을 활용한 멀티 클라우드 통합 관리 아키텍처 다이어그램.

Ansible, 왜 멀티 클라우드 자동화에 최적일까요?

먼저 Ansible이 어떤 녀석인지, 그리고 왜 멀티 클라우드 환경에 딱 맞는지 간단히 짚고 넘어가죠. 쉽게 말해 Ansible(앤서블)에이전트리스(Agentless) 기반의 자동화 도구(Automation Tool)입니다. 관리 대상 서버에 별도의 에이전트를 설치할 필요 없이 SSH(Secure Shell)나 WinRM(Windows Remote Management) 프로토콜을 이용해 명령을 실행하죠. 이게 멀티 클라우드 환경에서 엄청난 강점입니다.

  • 단일 제어 플레인(Single Control Plane): 각 클라우드 콘솔이나 CLI를 오갈 필요 없이, Ansible 컨트롤러 노드(Control Node) 하나에서 모든 클라우드 인프라를 관리할 수 있습니다.
  • 모듈(Modules) 기반의 추상화: Ansible은 각 클라우드 프로바이더(Cloud Provider)별로 수많은 모듈을 제공합니다. 예를 들어, AWS EC2 인스턴스를 만들 때는 amazon.aws.ec2_instance 모듈을, Azure VM을 만들 때는 azure.azcollection.azure_rm_virtualmachine 모듈을 사용하죠. 각 클라우드 API의 복잡성을 몰라도 모듈만 잘 사용하면 됩니다.
  • 멱등성(Idempotency): 플레이북(Playbook)을 여러 번 실행해도 항상 동일한 최종 상태(Desired State)를 보장합니다. 이미 생성된 리소스는 건드리지 않고, 필요한 변경사항만 적용되니 안심하고 재실행할 수 있습니다.
  • YAML(YAML Ain't Markup Language) 기반의 쉬운 학습 곡선: 복잡한 프로그래밍 언어 대신 사람이 읽고 쓰기 쉬운 YAML 문법으로 플레이북을 작성합니다. 인프라 엔지니어에게는 정말 친숙한 방식이죠.

결론적으로 Ansible은 코드로서의 인프라(Infrastructure as Code, IaC)를 구현하기에 아주 적합하며, 특히 이종 클라우드 환경을 통합 관리하는 데 강력한 성능을 발휘합니다.

실전 구현: AWS, Azure, GCP 인프라 자동화

자, 이제 직접 Ansible로 멀티 클라우드 인프라를 구축해볼 차례입니다. 목표는 각 클라우드에 웹 서버 역할을 할 가상 머신(Virtual Machine)을 하나씩 생성하고, 간단한 웹 서비스(Nginx)를 설치하는 것입니다.

1. Ansible 및 클라우드 연동 환경 설정

먼저 Ansible 컨트롤러 노드에 필요한 도구들을 설치해야 합니다. 저는 Ubuntu 환경에서 진행했습니다.

#!/bin/bash
# Ansible 설치
sudo apt update && sudo apt install -y ansible python3-pip

# AWS 연동을 위한 boto3 라이브러리 설치
pip3 install boto3 botocore

# Azure 연동을 위한 Azure CLI 및 모듈 설치
sudo apt install -y azure-cli
ansible-galaxy collection install azure.azcollection

# GCP 연동을 위한 Google Cloud SDK 및 모듈 설치
echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -
sudo apt update && sudo apt install -y google-cloud-sdk
ansible-galaxy collection install google.cloud

각 클라우드 인증 정보 설정도 중요합니다:

  • AWS: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY 환경 변수 설정 또는 ~/.aws/credentials 파일 설정
  • Azure: az login 명령으로 로그인 또는 서비스 주체(Service Principal) 생성 후 환경 변수 설정
  • GCP: 서비스 계정(Service Account) 키 파일 다운로드 후 GOOGLE_APPLICATION_CREDENTIALS 환경 변수 설정

⚠️ 인증 정보 관리 중요: 실제 운영 환경에서는 AWS Secrets Manager, Azure Key Vault, GCP Secret Manager 같은 비밀 관리 서비스(Secret Management Service)를 활용하거나 Ansible Vault를 사용하여 인증 정보를 안전하게 보관해야 합니다. 절대 민감한 정보를 플레이북에 직접 넣지 마세요!

2. 동적 인벤토리(Dynamic Inventory) 설정

클라우드 환경은 리소스가 수시로 생성/삭제되기 때문에 고정된 인벤토리 파일보다는 동적 인벤토리를 사용하는 것이 효율적입니다. Ansible은 각 클라우드 프로바이더를 위한 동적 인벤토리 플러그인을 제공하거든요.

# aws_ec2.yml (AWS EC2 인스턴스 동적 인벤토리)
plugin: amazon.aws.ec2
regions:
  - ap-northeast-2
keyed_groups:
  - key: tags.env
    prefix: env_

# azure_rm.yml (Azure VM 동적 인벤토리)
plugin: azure.azcollection.azure_rm
include_vm_resource_groups:
  - my-ansible-rg

# gcp_compute.yml (GCP Compute Engine 동적 인벤토리)
plugin: google.cloud.gcp_compute
projects:
  - your-gcp-project-id
zones:
  - asia-northeast3-a

이제 ansible-inventory -i aws_ec2.yml --list 등으로 각 클라우드의 인벤토리를 확인할 수 있습니다.

Ansible으로 생성된 각 클라우드 가상 머신 목록.

3. 클라우드 리소스 생성 플레이북 작성

각 클라우드에 가상 머신을 생성하고 Nginx를 설치하는 플레이북입니다. 하나의 플레이북에서 여러 클라우드를 대상으로 할 수 있다는 점이 핵심입니다.

---
# multi_cloud_infra.yml
# AWS, Azure, GCP에 동시에 웹 서버를 배포하는 플레이북

- name: AWS 인프라 준비
  hosts: localhost
  connection: local
  gather_facts: no

  vars:
    aws_region: ap-northeast-2
    ssh_key_path: ~/.ssh/id_rsa.pub

  tasks:
    # AWS Security Group 먼저 생성
    - name: AWS 보안 그룹 생성
      amazon.aws.ec2_security_group:
        name: ansible-sg-aws
        description: "Ansible managed AWS webserver security group"
        region: "{{ aws_region }}"
        rules:
          - proto: tcp
            ports: 22
            cidr_ip: 0.0.0.0/0
          - proto: tcp
            ports: 80
            cidr_ip: 0.0.0.0/0
        rules_egress:
          - proto: all
            cidr_ip: 0.0.0.0/0
      register: aws_sg_output

    # AWS EC2 인스턴스 생성
    - name: AWS EC2 인스턴스 생성
      amazon.aws.ec2_instance:
        name: ansible-aws-webserver
        image_id: ami-0c802847a7dd848c0  # Ubuntu 22.04 LTS (ap-northeast-2)
        instance_type: t2.micro
        region: "{{ aws_region }}"
        security_group: ansible-sg-aws
        key_name: your_aws_keypair
        tags:
          env: dev
          project: ansible-multi-cloud
        state: running
        wait: yes
      register: aws_ec2_output

- name: Azure 인프라 준비
  hosts: localhost
  connection: local
  gather_facts: no

  vars:
    azure_resource_group: my-ansible-rg
    azure_location: koreacentral
    ssh_key_path: ~/.ssh/id_rsa.pub

  tasks:
    # Azure Virtual Network 생성 (필수 선행 작업)
    - name: Azure Virtual Network 생성
      azure.azcollection.azure_rm_virtualnetwork:
        resource_group: "{{ azure_resource_group }}"
        name: ansible-vnet
        location: "{{ azure_location }}"
        address_prefixes:
          - "10.0.0.0/16"
      register: azure_vnet_output

    # Azure Subnet 생성
    - name: Azure Subnet 생성
      azure.azcollection.azure_rm_subnet:
        resource_group: "{{ azure_resource_group }}"
        name: default
        address_prefix: "10.0.0.0/24"
        virtual_network: ansible-vnet
      register: azure_subnet_output

    # Azure NSG 생성
    - name: Azure 네트워크 보안 그룹 생성
      azure.azcollection.azure_rm_networksecuritygroup:
        resource_group: "{{ azure_resource_group }}"
        name: ansible-azure-nsg
        location: "{{ azure_location }}"
        rules:
          - name: AllowSSH
            protocol: Tcp
            destination_port_range: 22
            access: Allow
            priority: 100
            direction: Inbound
          - name: AllowHTTP
            protocol: Tcp
            destination_port_range: 80
            access: Allow
            priority: 110
            direction: Inbound
      register: azure_nsg_output

    # Azure VM 생성
    - name: Azure VM 생성
      azure.azcollection.azure_rm_virtualmachine:
        resource_group: "{{ azure_resource_group }}"
        name: ansible-azure-webserver
        vm_size: Standard_B1s
        admin_username: azureuser
        ssh_password_enabled: false
        ssh_public_keys:
          - path: /home/azureuser/.ssh/authorized_keys
            key_data: "{{ lookup('file', ssh_key_path) }}"
        image:
          offer: 0001-com-ubuntu-server-jammy
          publisher: Canonical
          sku: 22_04-lts-gen2
          version: latest
        location: "{{ azure_location }}"
      register: azure_vm_output

- name: GCP 인프라 준비
  hosts: localhost
  connection: local
  gather_facts: no

  vars:
    gcp_project: your-gcp-project-id
    gcp_zone: asia-northeast3-a
    gcp_network: default
    ssh_key_path: ~/.ssh/id_rsa.pub
    gcp_user: ansible

  tasks:
    # GCP Firewall 규칙 생성
    - name: GCP 방화벽 규칙 생성
      google.cloud.gcp_compute_firewall:
        name: ansible-gcp-allow-http-ssh
        project: "{{ gcp_project }}"
        allowed:
          - IPProtocol: tcp
            ports: [ '22', '80' ]
        source_ranges: [ '0.0.0.0/0' ]
        target_tags: [ 'http-server' ]
        state: present
      register: gcp_fw_output

    # GCP Compute Engine 인스턴스 생성
    - name: GCP Compute Engine 인스턴스 생성
      google.cloud.gcp_compute_instance:
        name: ansible-gcp-webserver
        project: "{{ gcp_project }}"
        zone: "{{ gcp_zone }}"
        machine_type: e2-micro
        disks:
          - auto_delete: 'true'
            boot: 'true'
            initialize_params:
              source_image: projects/ubuntu-os-cloud/global/images/family/ubuntu-2204-lts
              disk_size_gb: 20
        network_interfaces:
          - name: "{{ gcp_network }}"
            access_configs:
              - name: "External NAT"
                type: "ONE_TO_ONE_NAT"
        metadata:
          ssh-keys: "{{ gcp_user }}:{{ lookup('file', ssh_key_path) }}"
        tags:
          items:
            - http-server
        state: present
      register: gcp_instance_output

- name: 모든 클라우드 웹서버에 Nginx 설치
  hosts: all
  gather_facts: yes

  pre_tasks:
    - name: SSH 연결 대기
      ansible.builtin.wait_for_connection:
        timeout: 300

  tasks:
    - name: Nginx 설치
      ansible.builtin.apt:
        name: nginx
        state: present
        update_cache: yes
      become: yes

    - name: Nginx 서비스 시작
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: yes
      become: yes

위 플레이북은 각 클라우드별로 분리된 구조로 작성되어 있습니다. 첫 번째부터 세 번째까지는 각각 AWS, Azure, GCP 인프라를 생성하는 hosts: localhost 플레이북입니다. 마지막 플레이북은 동적 인벤토리에서 수집된 모든 호스트에 Nginx를 설치합니다.

플레이북 실행은 간단합니다:

ansible-playbook -i aws_ec2.yml -i azure_rm.yml -i gcp_compute.yml multi_cloud_infra.yml

⚠️ 삽질 경험 및 트러블슈팅

제가 이 과정을 진행하면서 겪었던 몇 가지 삽질 경험과 해결 방법을 공유합니다. 여러분은 저처럼 헤매지 마시길 바랍니다. ㅎㅎ

1. 클라우드 인증 실패

문제: 플레이북 실행 시 Unauthorized, Access Denied, Credential Error 같은 메시지가 뜨면서 클라우드 리소스 생성이 안 되는 경우가 많았습니다.

해결:

  • AWS: ~/.aws/credentials 파일의 내용이 정확한지, 또는 환경 변수(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)가 올바르게 설정되었는지 확인했습니다. 그리고 해당 IAM 사용자에게 EC2 생성, Security Group 관리 등 필요한 권한이 제대로 부여되었는지 IAM 정책을 검토했습니다.
  • Azure: az login으로 로그인 세션이 유효한지 확인하거나, 서비스 주체(Service Principal)를 사용한다면 AZURE_CLIENT_ID, AZURE_SECRET, AZURE_TENANT, AZURE_SUBSCRIPTION_ID 환경 변수가 정확한지 확인했습니다. 해당 서비스 주체에 기여자(Contributor) 또는 그에 준하는 역할이 할당되어야 합니다.
  • GCP: 서비스 계정 키 파일(JSON)의 경로가 GOOGLE_APPLICATION_CREDENTIALS 환경 변수에 올바르게 지정되었는지 확인했습니다. 또한, 서비스 계정에 Compute Engine Instance Admin (v1), Service Account User 등 필요한 역할이 부여되어 있는지 GCP IAM 콘솔에서 확인했습니다.

2. SSH 접속 문제 (Nginx 설치 단계)

문제: 인스턴스는 잘 생성됐는데, Nginx 설치 단계에서 SSH Connection refused 또는 Timeout 에러가 발생했습니다.

해결:

  • 보안 그룹/방화벽 규칙: 각 클라우드에서 생성된 가상 머신의 보안 그룹(AWS), 네트워크 보안 그룹(Azure), 방화벽 규칙(GCP)에 Ansible 컨트롤러 노드의 IP 주소 또는 0.0.0.0/0(테스트용)에서 22번 포트(SSH) 접속을 허용하는 규칙이 있는지 확인했습니다.
  • SSH 키페어: 플레이북에서 지정한 ssh_key_path의 퍼블릭 키가 각 클라우드 인스턴스에 올바르게 등록되었는지 확인했습니다. AWS는 키페어 이름을, Azure/GCP는 직접 퍼블릭 키 내용을 전달하는 방식이므로 차이에 유의했습니다.
  • 사용자 이름: 각 클라우드 인스턴스의 기본 사용자 이름이 다릅니다. AWS Ubuntu는 ubuntu, Azure Ubuntu는 azureuser, GCP Ubuntu는 ubuntu로 설정했습니다. 플레이북에 ansible_user: 사용자명으로 명시하면 더 안전합니다.
  • 인스턴스 부팅 시간: 가끔 인스턴스가 완전히 부팅되기 전에 Ansible이 SSH 접속을 시도하여 실패하는 경우가 있습니다. ansible.builtin.wait_for_connection 모듈을 사용해 SSH 포트가 열릴 때까지 기다리도록 플레이북에 추가했습니다. 이건 정말 중요해요!

3. Azure 네트워크 구성 누락

문제: Azure VM을 생성하려니 Virtual Network와 Subnet이 없다고 에러가 나왔습니다.

해결: Azure는 AWS나 GCP와 달리 기본 네트워크 구조가 없으므로, VM 생성 전에 Virtual Network와 Subnet을 명시적으로 생성해야 합니다. 위의 플레이북에서 이를 추가했으니 참고하세요.

검증 및 결과 확인 ✅

플레이북 실행이 성공적으로 완료되었다면, 이제 각 클라우드 콘솔에 접속하여 리소스가 잘 생성되었는지 확인해볼 차례입니다. AWS EC2, Azure VM, GCP Compute Engine 목록에서 ansible-aws-webserver, ansible-azure-webserver, ansible-gcp-webserver라는 이름의 인스턴스가 실행 중인 것을 볼 수 있을 겁니다.

각 인스턴스의 퍼블릭 IP 주소로 웹 브라우저에서 접속해보세요. Nginx 기본 페이지가 보인다면 성공입니다! 드디어 됐다! 🎉

이 과정에서 여러분이 직접 각 클라우드의 콘솔을 열어 인스턴스를 생성하고, 보안 그룹을 설정하고, SSH로 접속해서 Nginx를 설치하는 수고를 덜 수 있었다는 것을 체감할 수 있을 겁니다. 자동화의 힘은 정말 대단하죠.

성공적으로 배포된 Nginx 웹 서버 페이지.

마무리하며: 클라우드 여정의 다음 단계

오늘은 Ansible을 활용해서 AWS, Azure, GCP 멀티 클라우드 환경에 인프라를 자동화하고 웹 서버를 배포하는 과정을 함께 해봤습니다. 제가 직접 해보니, 처음엔 각 클라우드 모듈과 인증 방식에 적응하는 데 시간이 좀 걸렸지만, 한 번 체계를 잡아두니 그 이후부터는 정말 편하더라고요. 삽질 끝에 얻은 귀한 경험이었습니다. 💡

이 글이 여러분의 멀티 클라우드 여정에 작은 등대가 되었기를 바랍니다. 여기서 멈추지 않고, 더 나아가 다음과 같은 내용들을 탐구해보시면 좋을 것 같습니다:

  • Ansible Vault: 민감한 정보를 안전하게 관리하는 방법.
  • CI/CD 파이프라인 통합: GitOps 워크플로우를 통해 변경 사항이 자동으로 배포되도록 구성.
  • Terraform과의 연동: Terraform으로 인프라를 프로비저닝하고, Ansible로 프로비저닝된 인스턴스에 소프트웨어를 구성하는 하이브리드 접근 방식.
  • 삭제 플레이북: 생성된 리소스를 깔끔하게 정리하는 삭제 플레이북 작성 (state: absent 활용).

저도 홈랩에서 이런저런 실험을 계속하면서 새로운 인사이트를 얻고 있습니다. 다음번에는 더 재미있고 유익한 경험담으로 찾아뵙겠습니다. 혹시 이 글을 읽으시면서 궁금한 점이나 공유하고 싶은 삽질 경험이 있으시다면 언제든지 댓글로 남겨주세요! 감사합니다!

Ansible을 통한 멀티 클라우드 자동화 요약.