[OpenStack Project] VMware 없이 노트북 서버로 kolla-ansible OpenStack 설치 [4]

KH55S·2025년 12월 17일

OpenStack Project

목록 보기
4/8

서론

  • [1] GitOps 기반의 프라이빗 클라우드 프로비저닝 자동화 : GitHub Actions + Self-Hosted Runner를 이용한 CI/CD 파이프라인 구축
    • GitLab을 사용하려고 했지만, 16GB RAM으로 GitLab서버를 구동하기가 어려워서 아키텍처와 동작 원리가 동일한 Github Actions의 Self-Hosted Runner 방식을 채택했다.
    • 리소스 제약으로 인해 GitLab 대신 GitHub Actions를 사용했으나, On-premise 인프라 내부에 Runner를 두어 보안과 접근성을 확보하는 원리는 동일하게 구현하였다.
  • [2] Packer를 사용하여 OS 설치 및 기본 설정이 완료된 Golden Image 생성 및 Glance에 등록하는 파이프라인 구축

  • IaC에서의 CI/CD 개념 간단 정리
    • CI : 작성한 Ansible Playbook이나 변수 파일의 문법 오류를 검사하고, 저장소에 병합하는 과정
    • CD : 변경된 코드를 감지하여 자동으로 ansbile-playbook 명령어를 실행해 실제 오픈스택 인프라에서 반영하는 과정
  • Self-Hosted Runner
    • 일반적인 Github Actions는 Github가 제공하는 클라우드 서버(Azure VM)에서 실행된다. 하지만 오픈스택은 로컬 노트북(사설망)에 설치되어 있다. Github 클라우드에서는 노트북 IP로 접속할 수 없다.
    • 오픈스택 제어 노드인 노트북에 Runner를 설치한다.
    • Long Polling : Runner는 Github 서버와 연결을 맺고 자신에게 할당된 작업이 있는지 계속 물어본다.
    • Github에 코드가 푸시되면, Github는 Runner에게 신호를 준다. Runner는 노트북 내부에서 스크립트를 실행한다.
    • 결과 : Runner가 로컬 네트워크에 있는 오픈스택 API를 호출하여 배포를 수행한다.

과정(1)

  • Self-Hosted Runner 설치
  1. Github에서 리포지토리를 생성 후 Settings > Actions > Runners로 이동
  2. [New self-hosted runner] 버튼을 클릭
  3. 화면에 나오는 명령어를 노트북 터미널에서 순서대로 복사해 실행
  4. 설치가 끝나면 ./run.sh를 실행하여 Runner를 Listening 상태로 만든다.

GitHub Runner 백그라운드 실행 방법 (Systemd 서비스로 등록)

# Runner가 설치된 폴더에서 
$ sudo ./svc.sh install
$ sudo ./svc.sh start
# 상태 확인
$ sudo ./svc.sh status
# 삭제
$ sudo ./svc.sh stop
$ sudo ./svc.sh uninstall
  • Github Secrets 설정
    • 오픈스택 인증 정보(clouds.yml)와 SSH 키를 Secrets 기능을 통해 파이프라인 실행 시점에 주입한다.
    1. GitHub 저장소 Settings > Secrets and variables > Actions
    2. [New repository secret]
    3. CLOUDS_YAML : ~/.config/openstack/clouds.yaml
      SSH_PRIVATE_KEY : ~/.ssh/id_ecdsa
  • 파이프라인 워크플로우 작성 (deploy.yml)
    • .github/workflows/deploy.yml
  name: OpenStack CD Pipeline

on:
  push:
    branches: ["main"]

jobs:
  deploy:
    runs-on: self-hosted

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Create clouds.yml
        run: |
          mkdir -p ~/.config/openstack
          echo "${{ secrets.CLOUDS_YAML }}" > ~/.config/openstack/clouds.yml

      - name: Setup SSH Key
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ecdsa
          chmod 600 ~/.ssh/id_ecdsa
          ssh-keygen -y -f ~/.ssh/id_ecdsa > ~/.ssh/id_ecdsa.pub

      - name: Run Ansible Playbook
        run: |
          source /home/name/openstack-venv/bin/activate  # 가상환경 활성화
          ansible-playbook provision_vm.yml


트러블 슈팅(1)

  • 로컬에 있는 SSH 개인키 파일의 내용이 사라짐
    • 상황 : cat 명령어로 SSH 개인키 내용을 확인했을 때 {{ secrets.SSH_PRIVATE_KEY }} 만 출력된다.
    • 원인1 : echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ecdsa 부분에서 { 앞에 $를 넣지 않았다.
    • 원인2 : Github Actions 파이프라인이 로컬에서 돌면서, Secrets을 제대로 불러오지 못한 채로 명렁어를 실행해서 원본 키 파일을 변수명 텍스트로 덮어씌웠다.
    • 해결 : 원래 키를 복수할 수 없으므로, 새로운 키를 생성
    rm ~/.ssh/id_ecdsa ~/.ssh/id_ecdsa.pub
     ssh-keygen -t ecdsa -b 521
     cat ~/.ssh/id_ecdsa
  • 파이프라인 동작 에러 : `Run ansible-playbook provision_vm.yml
    /home/name/actions-runner/_work/_temp/3c6f12a4-380c-48ee-95a4-9c6746364664.sh: line 1: ansible-playbook: command not found
    Error: Process completed with exit code 127
    • 원인 : GitHub Actions Runner는 내가 터미널에서 작업할 때 켜두었던 가상환경(openstack-venv)을 자동으로 켜주지 않기 때문이다.
    • Runner는 Shell 상태에서 명령어를 실행하는데, 이 상태에서는 ansible-playbook이 어디에 설치되어 있는지 모른다.
    • 해결 : 스크립트 안에서 가상환경을 활성화해주는 코드를 추가
      • 노트북 터미널에 가상환경이 켜진 상태로 Ansible이 어디에 설치되어 있는지 확인한다.
      which ansible-playbook
      /home/name/openstack-venv/bin/ansible-playbook
      • Run Ansible Playbook 단계에 source /home/name/openstack-venv/bin/activate를 추가하여 가상환경을 활성화한다.

과정(2)

  • Packer : HashiCorp사에서 만든 머신 이미지 자동 빌드 도구
    • 설정 파일 하나로 AWS AMI, Docker Image, OpenStack Image 등 다양한 플랫폼의 이미지를 자동으로 생성해 준다.
    • 배포 시간 단축 : VM을 켜고 apt update, nginx install 등을 직접 수행하지 않고 미리 다 설치된 이미지를 사용하여 빠르게 부팅 가능
    • 멀티 클라우드 : 같은 설정을 AWS용 이미지, 오픈스택용 이미지로 동시에 뽑아낼 수 있다.
    • 동작 과정
      • Builder : 오픈스택 API를 호출하여 임시 VM을 생성한다. (IP 할당, SSH 키 등록 등 자동 수행)
      • Provisioner : 생성된 VM에 SSH로 접속하여 사용자가 정의한 스크립트를 실행해 패키지를 설치한다.
      • Post-Processor : 설치가 끝나면 VM을 끄고 스냅샷을 생성한다. 이 스냅샷을 이미지로 등록한다.
      • Artifact : 최종 결과물인 이미지 ID를 출력하고 종료한다.
    • Packer는 기본적으로 자동 삭제를 수행한다.
      • 성공 시 : 이미지를 성공적으로 추출한 후, 빌드에 사용했던 임시 VM, Floating IP, Keypair, Security Group 등을 즉시 삭제한다.
      • 실패 시 : 빌드 도중 에러가 나더라도 기본적으론은 자원을 삭제하려고 시도한다. (디버깅을 위해 -on-error=abort 옵션을 쓰면 삭제하지 않고 남겨둘 수도 았다.)

  • cirros 이미지는 테스용 초소용 OS라서 패키지 설치가 불가능하기 때문에 Ubuntu Cloud Image를 준비한다.
# Ubuntu 22.04 Cloud Image 다운로드
$ wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img

# Glance에 등록
$ source /etc/kolla/admin-openrc.sh
  openstack image create "ubuntu-22.04-base" \
  --file jammy-server-cloudimg-amd64.img \
  --disk-format qcow2 \
  --container-format bare \
  --public

  • Packer 설치
# HashiCorp GPG 키 추가
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg

# 리포지토리 추가
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list

# 설치
sudo apt update && sudo apt install packer

  • Packer 템플릿 작성 (ubuntu-nginx.pkr.hcl)
packer {
  required_plugins {
    openstack = {
      version = ">= 1.0.0"
      source  = "github.com/hashicorp/openstack"
    }
  }
}

variable "cloud_name" {
  type    = string
  default = "my-openstack" # clouds.yaml에 정의된 이름
}

source "openstack" "ubuntu_nginx" {
  cloud      = var.cloud_name
  image_name = "ubuntu-nginx-golden-{{timestamp}}" # 생성될 이미지 이름

  source_image = "ubuntu-22.04-base"

  flavor = "m1.small"
  network_discovery_cidrs = ["10.0.0.0/24"]
  floating_ip_network = "ext_net"

  ssh_username = "ubuntu"
  use_blockstorage_volume = true
  volume_size = 10
}

build {
  sources = ["source.openstack.ubuntu_nginx"]

  provisioner "shell" {
    inline = [
      "sudo apt-get update",
      "sudo apt-get install -y nginx",
      "sudo systemctl enable nginx",
      "echo '<h1>Welcome to Golden Image created by Packer</h1>' | sudo tee /var/www/html/index.html"
    ]
  }
}
  • source "openstack" : Packer가 오픈스택 API를 호출하여 임시 VM을 생성한다. 이때 Floating IP를 자동으로 할당하여 인터넷 연결을 확보한다.
  • provisioner "shell" : VM이 부팅되면 SSH(ubuntu 계정)로 접속하여 apt-get 명령어들을 실행한다. 이 단계에서 Nginx가 설치된다.
  • Snapshot & Artifact : 설정이 끝나면 Packer는 VM을 중지하고 스냅샷을 생성한다. 이 스냅샷을 Glance에 업로드하고, 임시 VM과 Floating IP는 자동으로 삭제한다.

  • 로컬 테스트
# 초기화 (플러그인 다운로드)
$ cd ~/openstack-ansible-project/packer
$ packer init .

# clouds.yaml 경로 지정 
$ export OS_CLIENT_CONFIG_FILE=~/.config/openstack/clouds.yml

$ packer build ubuntu-nginx.pkr.hcl

  • Github Actions 파이프라인 생성 (.github/workflows/build_image.yml)
name: Build Golden Image with Packer

on:
  push:
    paths:
      - 'packer/**'
    branches: ["main"]
  workflow_dispatch:

jobs:
  packer-build:
    runs-on: self-hosted

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Create clouds.yml
        run: |
          mkdir -p ~/.config/openstack
          echo "${{ secrets.CLOUDS_YAML }}" > /home/name/.config/openstack/clouds.yml

      - name: Packer Init
        run: |
          cd packer
          /usr/bin/packer init .

      - name: Packer build
        env:
          OS_CLIENT_CONFIG_FILE: /home/name/.config/openstack/clouds.yml
        run: |
          cd packer
          /usr/bin/packer build ubuntu-nginx.pkr.hcl

0개의 댓글