용어
본격적으로 들어가기 전에, 짚고 넘어갈 만한 용어가 몇 가지 있습니다.
- Ansible Collection — 롤, 모듈, 플러그인을 담을 수 있는 자동화 묶음입니다. 대부분의 모듈은 Python(리눅스 서버와 네트워크 장비용) 또는 PowerShell(윈도우용)로 작성됩니다.
- Ansible Role — 미리 정의된 작업 모음으로, 변수, 템플릿, 파일, 핸들러를 포함할 수 있습니다. 롤은 컬렉션 안에 포함될 수도 있고 독립적으로 존재할 수도 있습니다.
- Config as Code (CaC) — 설정을 코드로 정의하고 관리하는 방식으로, 수동 설정 대신 자동화와 재사용, 버전 관리를 가능하게 합니다.
소개
저는 Kristian이고, Semaphore UI 설치 환경을 코드로 관리하는 Ansible Collection인 ebdruplab.semaphoreui의 작성자입니다.
어떻게 시작되었나
이 프로젝트는 Ansible을 더 깊이 이해하기 위한 방법으로 시작되었습니다. 그때까지 저는 주로 다른 사람이 만든 컬렉션과 롤을 가져다 쓰거나, ansible.builtin.cmd와 register, Jinja2 템플릿을 엮어서 일을 처리하곤 했습니다.
호기심에 처음 불이 붙은 건 다소 생소한 네트워크 장비를 자동화해야 했던 때였습니다. 구체적으로는 데이터베이스의 시리얼 번호가 올바르게 설정되었는지 검증하는 일이었죠. 그 프로젝트가 끝난 뒤에는 늘 하던 PowerShell 작업으로 돌아갔지만, 새로운 컨설팅 업무가 저를 다시 Ansible로 이끌었습니다. 그 업무에는 패치 관리부터 Ansible 노드 구축 지원, 모범 사례 자문, Red Hat Single Sign-On 설치용 콘텐츠 제작까지 모든 것이 포함되어 있었습니다.
Ansible과 함께한 지 7년이 되었습니다. CLI로 시작해 Ansible Automation Platform(AAP) v2로 넘어갔다가 결국 그것에서 멀어졌습니다. 왜냐고요? AAP는 강력하지만 무거운 제품이고, 대기업을 위해 만들어졌습니다. OpenShift 밖에서 구축하기가 고통스럽고, 라이선스 비용도 그에 걸맞습니다.
왜 Semaphore UI인가
Semaphore UI는 단순함으로 저를 사로잡았습니다. 패키지 하나, 서버 한 대(엔터프라이즈 규모가 필요하지 않다면)면 충분합니다. 열 개의 포트로 열 가지 방식으로 통신하는 여섯 대의 VM은 필요 없습니다.
물론 AAP의 execution environments는 우아합니다. 하지만 그것을 유지 관리하는 일은 또 다른 이야기입니다. Semaphore UI는 패치도 쉽고 운영도 쉬우며, 반응이 빠르고 직관적인 인터페이스를 제공합니다. 고급 기능이 일부 빠져 있는 것은 사실이지만, 제 사용 사례에서는 기능과 비용의 균형이 딱 알맞습니다.
Semaphore는 홈랩 커뮤니티에서 처음 들었고, 직접 써보기 전까지는 별로 신경 쓰지 않았습니다. 그러다 Ansible Galaxy를 확인해 보니 관련 컬렉션이 없었고, 결정은 쉬웠습니다. 이것을 제 학습 프로젝트로 삼기로 한 것이죠. 코드를 전부 제가 직접 썼냐고요? 아닙니다. 처음부터 끝까지 AI의 도움을 받았습니다. 하지만 프로젝트는 조금씩 형태를 갖춰 갔습니다. 여기서 30분, 저기서 한 시간. 얼마 지나지 않아 Semaphore API 전체를 Python 모듈로 옮겨 놓았습니다.

무엇을 할 수 있나
ebdruplab.semaphoreui로 무엇을 할 수 있는지는 Ansible Galaxy에 예제가 있습니다. 여기서도 몇 가지 소개합니다.
프로젝트 생성과 관리 — Semaphore 프로젝트를 코드로 정의하고 반복 가능하게 배포합니다
- name: Create project with token and custom settings
ebdruplab.semaphoreui.project_create:
host: http://localhost
port: 3000
api_token: "{{ semaphore_token }}"
name: "My Project"
alert: true
alert_chat: "#alerts"
max_parallel_tasks: 5
demo: false
인벤토리 구성 — 정적·동적 인벤토리를 프로그래밍 방식으로 관리합니다
- name: Create static inventory
ebdruplab.semaphoreui.project_inventory_create:
host: http://localhost
port: 3000
session_cookie: "{{ login_result.session_cookie }}"
project_id: 1
inventory:
name: "Local Static Inventory"
type: "static"
inventory: "localhost ansible_connection=local"
ssh_key_id: 42
become_key_id: 7
작업 템플릿 설정 — UI를 건드리지 않고 템플릿을 만들고 업데이트합니다
- name: Create template with UI-style override flags
ebdruplab.semaphoreui.project_template_create:
host: http://localhost
port: 3000
api_token: "{{ semaphore_token }}"
project_id: 1
template:
name: "ff"
playbook: "f"
repository_id: 1
inventory_id: 1
environment_id: 1
type: ""
arguments: "[]"
task_params:
allow_override_tags: true
allow_override_limit: true
tags: ["t"]
limit: ["t"]
사용자 관리 — 사용자 생성과 프로젝트 배정을 자동화합니다
- name: Create a new user
ebdruplab.semaphoreui.user_create:
host: http://localhost
port: 3000
session_cookie: "{{ login_result.session_cookie }}"
name: "Jane Smith"
username: "jsmith"
email: "[email protected]"
password: "supersecure123"
admin: true
alert: true
기존 프로젝트 백업 — 운영 중인 프로젝트를 YAML로 내보내 버전 관리에 넣습니다
- hosts: localhost
gather_facts: false
roles:
- role: ebdruplab.semaphoreui.project_backup
vars:
project_backup_semaphore_host: "https://semaphore.example.com"
project_backup_semaphore_api_token: "{{ lookup('env', 'SEMAPHORE_TOKEN') }}"
project_backup_project_name: "My Project"
복원 또는 마이그레이션 — YAML 정의로부터 프로젝트 전체 구성을 몇 초 만에 다시 배포합니다.
- hosts: localhost
gather_facts: false
vars_files:
- vars/project.yml
roles:
- role: ebdruplab.semaphoreui.project_deploy
Config as Code — ebdruplab.project_deploy
모듈 하나가 둘이 되었고, 둘이 열이 되었습니다. 결국 컬렉션은 프로젝트, 템플릿, 인벤토리를 비롯한 여러 영역을 아우르는 92개 모듈에 이르렀습니다.
어느 시점에 한 사용자가 이 모든 모듈을 이어 줄 접착제 역할의 롤을 요청했습니다. 그렇게 만들어진 롤이 ebdruplab.project_deploy입니다. Semaphore UI 프로젝트가 어떤 모습이어야 하는지 정확히 정의한 다음, Ansible을 통해 선언적으로 생성할 수 있습니다.



최소한의 프로젝트 정의는 다음과 같습니다.
project_deploy_config:
project:
name: "My Project"
alert: false
alert_chat: ""
max_parallel_tasks: 0
demo: false
users_access:
- username: "admin"
role: "Owner"
keys:
repo_login:
name: "Git Login"
type: login_password
login_password:
login: "git-user"
password: "{{ vault_git_password }}"
repositories:
- name: "Example Repo"
git_url: "https://github.com/example/repo.git"
git_branch: "main"
key_name: "Git Login"
views:
main:
title: "Main"
position: 0
inventories:
local_inventory:
name: "Local Inventory"
type: "static"
inventory: "localhost ansible_connection=local"
environments:
default_env:
name: "Default Environment"
env:
APP_ENV: "prod"
templates:
deploy_job:
name: "Deploy"
type: "job"
repository_name: "Example Repo"
inventory_name: "Local Inventory"
environment_name: "Default Environment"
view_title: "Main"
playbook: "playbooks/site.yml"
schedules: {}
integrations: {}
문서는 Ansible Galaxy에서 볼 수 있고, GitHub 저장소의 project_deploy와 project_backup 안에는 시작에 도움이 되는 examples/ 및 test/ 폴더가 들어 있습니다.
Config as Code 변환기 — ebdruplab.project_backup
project_deploy를 만든 뒤 또 다른 생각이 들었습니다. 코드로 만들어지지 않은 기존 Semaphore 프로젝트는 어떻게 할 것인가? 바로 그 문제를 풀기 위해 ebdruplab.project_backup을 만들었습니다. 기존 프로젝트를 가져와 project_deploy와 호환되는 YAML 변수 파일로 내보내 줍니다.
이로써 순환이 완성됩니다. 처음부터 시작하든 기존 환경을 옮기든, 모든 것을 버전 관리 아래 둘 수 있습니다.


시작하기
명령 하나로 컬렉션을 설치할 수 있습니다.
ansible-galaxy collection install ebdruplab.semaphoreui
그다음 Ansible Galaxy의 전체 문서를 확인하거나 GitHub의 예제를 살펴보세요.
오류를 발견했거나 아이디어가 있다면 주저하지 말고 issue/feature/question을 남겨 주세요 — https://github.com/Ebdruplab/ansible-collection_ebdruplab/issues. 그 밖에는 보통 Semaphore UI Discord 서버 근처에 있습니다 — TrimmerWolf7.
이 컬렉션이 도움이 되기를 바랍니다.