AOC55

Cloud, Devops, Backend, Kubernetes, Openstack, ...

Cloud/Openstack

Openstack :: Heat Study (1)

aoc55.soft@gmail.com 2025. 5. 17. 16:59

 

개인적으로 공부하는 관점에서 작성한 내용이라, 잘못된 부분이 있을 수 있습니다. 잘못된 부분은 말씀주시면 감사하겠습니다

본 내용은 아래 자료를 기반으로 학습하면서 작성했습니다.

Heat Concept

Heat는 결국 Orchestrtation as a Service를 위한 Openstack Component!

이를 위해 Template 을 통해 정의하고,Stack 이라는 실제 Instance를 생성해서 구성 및 관리하는 것으로 보인다.

"HOT" (Heat Orchestration Template)

  • YAML or JSON으로 작성이 가능한데, 대부분 YAML 으로 작성 하는 것으로 보임
  • 특징으로 AWS CloudFormation 호환이 됨
  • Template 구성 시 조건부/조건문, 중첩구조 등이 가능함
(참고) AWS CloudFormation 호환 관련해서는, 공식 Component Docs 내 아래와 같은 문구도 볼 수 있음

현재 OpenStack에는 CloudFormation을 구현한 다른 프로젝트가 존재하지 않습니다. 개발자들은 클라우드 개발자들이 AWS에서 OpenStack 배포 환경으로 워크로드를 이전하고자 하는 강한 요구가 있다고 믿고 있습니다. OpenStack에서 잘 구현되고 통합된 CloudFormation API가 부재한 상황에서, 우리는 이 공백을 메우는 고품질 구현을 제공함으로써 OpenStack의 보편성을 향상시키고자 합니다.

"Stack"

  • HOT Template에 정의된대로 생성된 실제 Infrastructure (Server, Network, Port...)들을 의미
  • 단, 위 HOT 통해서 일관되고 반복적으로 여러 Stack생성 등이 가능하다. (쓰는 이유 중 가장 중요한 점일듯..)

 

또한 중요한 기능으로 Stack 리소스 기반으로 Auto Scaling 기능을 지원함.

  • 단, Auto Scaling을 위해서는 Metrics 등이 수집되고 관리되어야 하는데 이를 위해서 Ceilometer, Aodh 등과 같은 요소들이 함께 필요한 것으로 보임.

Heat 사용에 대한 장점

대부분의 Application은, 단일 Layer가 아닌 Mutli Layer 기반으로 구성됨.
이를 위해서는(Application 의) Infrastructure 관점에서도 복잡한 구조를 가지게 됨.

하지만 WEB - WAS - DB 와 같은 (이제는.. Classiscal 하지만...) 3 Layer 구조를 Openstack 에서 형성하기 위해서는... (짧게 생각해도) 아래와 같이 Openstack 관점에서는 많은 구성 작업들이 필요함.

예시

  • Layer 별로 Network 혹은 Subnet 을 분리하고,
  • 서로 통신이 가능하도로 Router를 생성한 뒤 각각의 Subnet을 연결하고,
  • Port를 생성하는데, 추가로 Security Group 등으로 ACL을 제어하고,
  • 이후 각각 Server, Volume을 생성하고,
  • 또한 Ocatavia 기반의 LB를 연결하고...
  • 등등등 ........

하지만 Heat 를 통해서, 위와 같은 복잡한 구조의 인프라 배포 및 구성을 (Openstack 관점에서) 쉽게 할 수 있음

거기에 Template 구조를 통해서 Auto Scaling 뿐만아니라, 장애 등의 상황에서 자동으로 리소스 복구가 가능한 구조임.

즉, 관리의 단순화 + 인프라스트럭처 배포 및 운영의 자동화 등의 장점이 있음


Heat Architecture

Heat Services

ref. https://docs.openstack.org/heat/latest/developing_guides/architecture.html

Heat 를 구성하기 위해서 어떠한 Service 들이 구성되어 있는가?

heat

  • Heat 서비스들에 대한 CLI 도구
  • heat-api
  • Openstack Natvie 한 Heat API 제공의 역할 (즉, api-server)
  • API 요청을 수신할 경우 RPC 통신을 통해, heat-engine Service를 호출하는 구조

heat-api-cfn

  • (참고) cfn -> "CloudFormation"
  • AWS CloudFormation과 호환되는 AWS Query API를 제공하는 목적
  • 역시 동일하게 API 요청 수신 시, RPC 통신으로 Heat Engine 으로 전송

heat-engine

  • Orchestrate (template 실행 등)에 대한 Main 책임을 가지는 서비스임.
  • 오케스트레이션 관련해서 API Consumer에게 Event 제공도 해주고 있음

Heat Agent를 활용한 Configuration

주 목적은 배포 된 Server 내에 (Agent 기반으로) 필요한 "Software Configuration" 을 실행하기 위함.
즉, Heat를 통해서 Infrastrucutre의 배포 뿐만 아니라, Software Config 까지 수행이 가능하다.
(간단한 예시로 특정 패키지 설치, 설정파일 배포, 특정 커맨드 실행)

단, 이를 위해서 생성한 Server 내 아래와 같은 Agent 설치 및 구성이 필요하다.
Server 내에서 Agent 설치를 위해선, Agent 설치는 Cloud-Init을 사용하거나 사전 설치 후 전용 Image 를 구성하는 등의 방식이 필요해보임

Heat Agent

  • Template -> Stack 으로 생성된 Server 내부에서 동작하는 Agent.
  • Agent 종류
    • os-collect-config
      • 설정 데이터 수집
    • os-refresh-config
      • 변경 설정 감지 -> os-apply-config 실행 트리거
    • os-apply-config
      • 수집된 설정데이터 기반으로 실제 파일 생성, 명령 실행 등 수행

Agent 구성 이후 사용 가능한,Template 리소스

  • Agent 구성 이후, Template 내에서 아래와 같은 리소스 타입 구성들을 통해서 필요한 작업을 구성할 수 있다.
    • type: OS::Heat::SoftwareConfig
    • type: OS::Heat::SoftwareDeployment

예시 Template

# 생략....
    resources:
      my_config:
        type: OS::Heat::SoftwareConfig
        properties:
          config: |
            #!/bin/bash
            echo "Hello from Heat" > /tmp/hello.txt

      my_deployment:
        type: OS::Heat::SoftwareDeployment
        properties:
          config: { get_resource: my_config }
          server: { get_resource: my_server }
# 생략....

Template -> Agent 기반의 실행 절차 요약

Heat Stack 생성 시
   ↓
heat-engine 이 SoftwareDeployment 리소스 생성
   ↓
heat-agent (예: os-collect-config) 가 주기적으로 설정 요청 확인
   ↓
설정 감지 시 os-apply-config 등을 통해 내부 명령 실행
   ↓
결과를 Heat API에 보고 (성공/실패 등)

Hands On

HOT (Heat Orchestration Template) 작성

Template 기본 구조

공식 Docs를 참고하면서 작성하면 된다.

Template 기본 구조

heat_template_version: 2016-10-14

description:
# a description of the template

parameter_groups:
# a declaration of input parameter groups and order

parameters:
# declaration of input parameters

resources:
# declaration of template resources

outputs:
# declaration of output parameters

conditions:
# declaration of conditions

heat_template_version

  • Template 규격에 대한 Version 을 정의
  • 현재 작성 시점 기준으로는 2021-04-16가 마지막 최신 Version 인 것 같다.
  • 다만, 버전 별로 지원되는 템플릿 렌더링 메서드나 구조에서 차이가 있을 수 있으니 이 부분은 미리 확인이 필요해보인다.

resources

  • 해당 Template 을 통해서 생성할 실제 Resource들을 정의
  • ref. https://docs.openstack.org/heat/2025.1/template_guide/hot_spec.html#wallaby
  • resource 정의 시 위 문서를 참고해서, resource 별로 요구되는 properties 를 '직접' 혹은 '전달구조'로 전달해주면 된다.
  • 아래는 Network와 Subnet 에 대한 Resource 생성을 정의한 예시
# 생략 ...

  # Network
  test01_network:
    type: OS::Neutron::Net
    properties:
      name: test01_network

  # Subnet
  test01_subnet:
    type: OS::Neutron::Subnet
    properties:
      name: test01_subnet
      network: { get_resource: test01_network }
      cidr: { get_param: my_net_cidr }
      ip_version: 4

# 생략 ...

Network 생성 한 이후, 해당 Network 하위에 Subnet 을 생성한다.

  • Subnet 생성 시점에, 상위 Network 리소스 정보를 얻기 위해서 { get_resource: test01_network } 와 같이 구성.
  • cidr 는 CLI를 통해 Template 에서 stack 리소스 생성 시 직접 파라미터로 입력 받게 함. ({ get_param: my_net_cidr })
  • 이외에 propertiesname 과 같은 부분은 상수 하드코딩(?) 하였음.

 

직접 해본 예시 Template :: nginx 서버 구성하기

시나리오

  1. Tenant(self-service, overlay) Network 내 Web Server 역할을 수행할 Server(VM)를 생성하고,
  2. 사전에 정의한 외부 네트워크와 연결된 네트워크에서 Floating IP를 할당해서, 최종적으로는 외부에서 접근 가능한 Web Server를 배포하는 예시

각 Resource 별로 Properites (필수, optional ...) 등은 역시 공식 문서 참고하면서 작성

 

OpenStack Resource Types — openstack-heat 24.0.1.dev3 documentation

use_request_body_as_input Available since 6.0.0 (Mitaka) Defines the method in which the request body for signaling a workflow would be parsed. In case this property is set to True, the body would be parsed as a simple json where each key is a workflow inp

docs.openstack.org

 

샘플 Template

heat_template_version: 2018-08-31

description: "Simple Heat Test1"

parameters:
  # NW
  my_external_nw_name:
    type: string
    description: External Network ID for Router
  my_net_cidr:
    type: string
    description: Tenant Network cidr
  # Volume
  my_image_id:
    type: string
    description: Image ID for Instance
  my_volume_type:
    type: string
    description: Root Volume Type
  # Server
  my_public_key:
    type: string
    description: PublicKey
  my_flavor_id:
    type: string
    description: Flavor for Instance

resources:
  # Router
  test01_router:
    type: OS::Neutron::Router
    properties:
      name: test01_router
      external_gateway_info: {
        enable_snat: true,
        network: { get_param: my_external_nw_name }
      }

  # Network
  test01_network:
    type: OS::Neutron::Net
    properties:
      name: test01_network

  # Subnet
  test01_subnet:
    type: OS::Neutron::Subnet
    properties:
      name: test01_subnet
      network: { get_resource: test01_network }
      cidr: { get_param: my_net_cidr }
      ip_version: 4

  # Connect Subnet to Router
  router_interface:
    type: OS::Neutron::RouterInterface
    properties:
      router_id: { get_resource: test01_router }
      subnet_id: { get_resource: test01_subnet }

  # Security Group
  test01_sg:
    type: OS::Neutron::SecurityGroup
    properties:
      name: test01_sg
      rules:  [
        {
          direction: "ingress",
          ethertype: "IPv4",
          port_range_max: "80",
          port_range_min: "80",
          protocol: "tcp",
          remote_ip_prefix: "0.0.0.0/0",
          remote_mode: "remote_ip_prefix"
        },
        {
          direction: "egress",
          ethertype: "IPv4",
          port_range_min: "1",
          port_range_max: "65535",
          protocol: "tcp",
          remote_ip_prefix: "0.0.0.0/0",
          remote_mode: "remote_ip_prefix"
        },
        {
          direction: "egress",
          ethertype: "IPv4",
          port_range_min: "1",
          port_range_max: "65535",
          protocol: "udp",
          remote_ip_prefix: "0.0.0.0/0",
          remote_mode: "remote_ip_prefix"
        }
      ]

  # Port
  test01_port:
    type: OS::Neutron::Port
    properties:
      name: test01_port1
      network: { get_resource: test01_network }
      fixed_ips: [{ "subnet": { get_resource: test01_subnet } }]
      security_groups: [{ get_resource: test01_sg }]

  # Floating IP
  test01_fip:
    type: OS::Neutron::FloatingIP
    properties:
      floating_network: { get_param: my_external_nw_name }

  # ---

  # Keypair
  test01_keypair:
    type: OS::Nova::KeyPair
    properties:
      name: test01_keypair
      public_key: { get_param: my_public_key }

  # Root Volume
  test01_root_volume:
    type: OS::Cinder::Volume
    properties:
      name: test01_root_volume
      image: { get_param: my_image_id }
      size: 40
      volume_type: { get_param: my_volume_type } 

  # Server
  test01_server:
    type: OS::Nova::Server
    properties:
      name: test01_server
      key_name: { get_resource: test01_keypair }
      flavor: { get_param: my_flavor_id }
      block_device_mapping_v2: [
        {
          delete_on_termination: True,
          volume_id: { get_resource: test01_root_volume }
        }
      ]
      networks: [{ port: { get_resource: test01_port }} ]
      user_data:
        str_replace:
          template: |
            #!/bin/bash
            apt update
            apt install -y nginx
            systemctl enable nginx
            systemctl start nginx
          params: {}

  # Associate Floating IP
  test01_fip_associate:
    type: OS::Neutron::FloatingIPAssociation
    properties:
      floatingip_id: { get_resource: test01_fip }
      port_id: { get_resource: test01_port }

outputs:
  test01_server:
    value: { get_attr: [ test01_server, name, networks ]}
  floating_ip:
    value: { get_attr: [ test01_fip, floating_ip_address ]}
  • VM 내 Nginx 구성은, 간단히 Cloud-Init 스크립트 기반으로 구성!

 

Heat CLI

Template 에서 Stack 생성하기

우선, 작성한 Template에 오류가 없는지 검증하기 위해, Template 에서 정의한 parameter 들을 같이 전달해서 validate 를 수행해보자.

openstack orchestration template validate -t /heat01.yaml \
  --parameter my_external_nw_name='provider-nw' \
  --parameter my_net_cidr='192.168.100.0/24' \
  --parameter my_image_id='c2ffc3d6-b84e-4fb6-a708-7e8562eeee10' \
  --parameter my_volume_type='rbd1' \
  --parameter my_flavor_id='29eb198c-e2ae-44e6-bce2-6f1b3fdb987b' \
  --parameter my_public_key="$(cat /test.pub)"
  • Heat 템플릿 문법 및 리소스 검증을 수행
  • 별도의 오류가 없다면, 정상적으로 템플릿 구조 요약 출력

위에서 정의한 Template 파일를 통해서 실제로 stack 리소스를 생성하자.

openstack stack create -t /heat01.yaml \
  --parameter my_external_nw_name='provider-nw' \
  --parameter my_net_cidr='192.168.100.0/24' \
  --parameter my_image_id='c2ffc3d6-b84e-4fb6-a708-7e8562eeee10' \
  --parameter my_volume_type='rbd1' \
  --parameter my_flavor_id='29eb198c-e2ae-44e6-bce2-6f1b3fdb987b' \
  --parameter my_public_key="$(cat /test.pub)" \
  my-stack-01  --wait

CLI 실행 결과

 

생성된 리소스 구성

Stack 조회, 삭제 등..!

이후 필요에 따라 생성한 stack 리소스에 대해서 조회, 삭제 등을 수행이 가능

# Stack 리스트 조회
openstack stack list

# Stack 상세 조회
openstack stack show <stack-name>

# 특정 Stack Event 조회
openstack stack evnet list <stack-name>

# 특정 Stack 삭제
openstack stack delete <stack-name>
# 그외 등...

Next🤨 ...

다음 편에 이어서 해보거나, 아직은 궁금한 것들!

  • Ceilometer 와 연계해서, Auto Scaling 등 해보기!
  • Heat engine 은 어떤 내부 구조로 리소스들이 생성되는 것을 감지하고 넘어가는 것일까?
  • 템플릿에서 -> 리소스 생성을 위한 Graph 구성은 어떤 방식으로 하는 것일까?

'Cloud > Openstack' 카테고리의 다른 글

Openstack :: Nova Cell 이란?  (0) 2025.10.18
Openstack :: Nova의 Service 목록과 Status & State  (0) 2025.09.23
Openstack :: Keystone System Role  (0) 2025.02.16
Openstack :: barbican 이란?  (1) 2025.02.08