テンプレートを使用したサンプルシステムの構築[東日本/西日本リージョン3向け]#

要求事項#

仮想サーバや仮想ネットワーク、ファイアーウォールやセキュリティグループのルール等、何度も利用する構成を定型化することで以下の要求事項に対応します。

  • システムを一括で配備したい(自動化)
  • 開発/検証/本番等の環境を同一の内容で構築したい
  • 他のシステムでも再利用できるようにしたい

本パターンではテンプレートを使用しサンプルシステムを構築することで、テンプレートを使用したスタック作成の概要と手順を理解することを目的とします。

対応するデザインパターン概要#

1. FJcloud-Oでのテンプレート#

FJcloud-Oでは、システム上で提供される複数の仮想リソースを使用して、環境を自動で構築するオーケストレーション機能が提供されています。

オーケストレーション機能では、仮想ルータ、サブネット等のネットワークの設定や、ロードバランサー、仮想サーバ等のサーバの設定、ファイアーウォールやセキュリティグループ等のアクセス制御設定等のシステムのかたまりを、スタックとして扱います。
このスタックをYAML形式のテキストで定義したものをテンプレートまたはHEATテンプレートと呼んでいます。

テンプレートをIaaSポータルやAPI経由で投入することで、オーケストレーション機能が働いてシステムを一括で構築することが出来ます。

2. テンプレートの書式#

テンプレートで使用されるYAMLとは構造化されたデータを表現するためのフォーマットです。
以下の3つの主要セクションで構成されます。

  • parameters:
    作成/設定するリソースの入力パラメータに関する記述
  • resources:
    作成/設定する固有のリソースに関する記述
  • outputs:
    アウトプットのパラメータに関する記述

構造 (イメージ図)#

以下サンプルシステムの構築を自動化するテンプレートを例として、スタックの作成、およびスタックの削除を記載します。
各リソースの名称は括弧内の値が付与されます。 image
※仮想ルータ(RT2)は外部ネットワークへの接続なし

実装サンプル#

1. スタックの作成#

(1) テンプレートの内容#

以下のサンプルテンプレートを使用してリソースの作成を行います。
parameters, resources, outputsセクション内の各オブジェクトに関して、以下の(B)~(D)の手順を参考として必要に応じたパラメータ修正やリソース数の増減を行ってください。

  • サンプルテンプレート
    heat_template_version: 2013-05-23
    description: A single-server deployment including inflastructures
    
    parameters:
    
    # Infla parameters
      service_network1_name:
        type: string
        description: Name of the service network
        default: NW2
        
      service_subnet1_name:
        type: string
        description: Name of the service subnetwork.
        default: SN2
        
      service_router1_name:
        type: string
        description: Name of the service vrouter.
        default: RT2
        
      service_subnet1_cidr:
        type: string
        description: CIDR representation of the service subnet.
        default: 192.168.2.0/24
        
      service_subnet1_gw_ip:
        type: string
        description: Gateway IP of Subnet
        default: 192.168.2.1
        
      service_subnet1_gw_port_name:
        type: string
        description: Gateway port name of Subnet
        default: GWport2
        
      security_group_name:
        type: string
        description: Security Group name
        default: SG2
        
      nameserver_ip1:
        type: string
        description: IP of the dns nameserver1.
        default: 8.8.8.8
        
      nameserver_ip2:
        type: string
        description: IP of the dns nameserver2.
        default: 9.9.9.9
        
      firewall1_name:
        type: string
        description: Name of the firewall1
        default: FW2
        
      firewall1_policy_name:
        type: string
        description: Name of the firewall1 Policy
        default: FWpolicy2
        
    # Server parameters
        
      port_name:
        type: string
        description: name of vm
        default: Port2
        
      key_name:
        type: string
        description: name of keypair
        default: Key2
        
      image:
        type: string
        description: Image ID or image name to use for the server
        default: 1e8d4a48-bbde-416f-b6fd-fff016673d6c
        
      volume_name:
        type: string
        description: name of volume
        default: Volume2
        
      flavor:
        type: string
        description: Flavor for the server to be created
        default: fdbf1331-9dfe-4119-872d-3b88d1cb61b8
        
      vm_name:
        type: string
        description: name of vm
        default: VM2
      
    
    resources:
    
    # Infla resources
      service_network1:
        type: OS::Neutron::Net
        properties:
          name: { get_param: service_network1_name }
          
      service_subnet1:
        type: OS::Neutron::Subnet
        properties:
          cidr: { get_param: service_subnet1_cidr }
          name: { get_param: service_subnet1_name }
          gateway_ip: { get_param: service_subnet1_gw_ip }
          network_id: { get_resource: service_network1 }
          dns_nameservers: [{ get_param: nameserver_ip1 }, { get_param: nameserver_ip2 }]
          
      gw_port1:
        type: OS::Neutron::Port
        properties:
          network_id: { get_resource: service_network1 }
          fixed_ips: [{"ip_address": {get_param: service_subnet1_gw_ip }, "subnet_id": {get_resource: service_subnet1 }}]
          name: { get_param: service_subnet1_gw_port_name }
          
      service_router1:
        type: OS::Neutron::Router
        properties:
          name: { get_param: service_router1_name }
          
      service_router_interface1:
        depends_on: service_router1
        type: OS::Neutron::RouterInterface
        properties:
          router_id: { get_resource: service_router1 }
          port_id: { get_resource: gw_port1 }
          
      security_group:
        type: OS::Neutron::SecurityGroup
        properties:
          description: test Security groups rule
          name: { get_param: security_group_name }
          rules: [{"direction": ingress, "port_range_max": 22, "port_range_min": 22, "protocol": tcp, "remote_ip_prefix": 192.168.2.0/24 },
                  {"direction": ingress, "protocol": icmp, "remote_ip_prefix": 192.168.2.0/24 }]
                  
      firewall1:
        type: OS::Neutron::Firewall
        properties:
          description: test Firewall
          name: { get_param: firewall1_name }
          firewall_policy_id: {get_resource: firewall1_policiy }
          value_specs: {"router_ids": [{get_resource: service_router1}]}
    
      firewall1_policiy:
        type: OS::Neutron::FirewallPolicy
        properties:
          audited: true
          description: test Firewall Policy
          firewall_rules: [{ get_resource: firewall_rule1 },{ get_resource: firewall_rule2 },{ get_resource: firewall_rule3 }]
          name: { get_param: firewall1_policy_name }
          
      firewall_rule1:
        type: OS::Neutron::FirewallRule
        properties:
          description: test Firewall rule1
          destination_port: "80"
          protocol: tcp
          source_ip_address: {get_param: service_subnet1_cidr}
          action: allow
          
      firewall_rule2:
        type: OS::Neutron::FirewallRule
        depends_on: firewall_rule1
        properties:
          description: test Firewall rule2
          source_port: "53"
          protocol: udp
          source_ip_address: {get_param: service_subnet1_cidr}
          destination_ip_address:  {get_param: nameserver_ip1}
          action: allow
          
      firewall_rule3:
        type: OS::Neutron::FirewallRule
        depends_on: firewall_rule1
        properties:
          description: test Firewall rule3
          source_port: "53"
          protocol: udp
          source_ip_address: {get_param: service_subnet1_cidr}
          destination_ip_address: {get_param: nameserver_ip2}
          action: allow
          
    # Server resources
          
      port:
        type: OS::Neutron::Port
        properties:
          name: { get_param : port_name }
          network_id: { get_resource: service_network1 }
          security_groups:
            - {get_resource: security_group }
          fixed_ips:
            - subnet_id: { get_resource: service_subnet1 }
            
      key:
        type: OS::Nova::KeyPair
        properties:
          name: { get_param: key_name }
          save_private_key: true
          
      sys-vol:
        type: OS::Cinder::Volume
        properties:
          name: { get_param: volume_name }
          size: 60
          volume_type: M2
          image : { get_param: image }
          
      server:
        type: OS::Nova::Server
        properties:
          key_name: { get_resource: key }
          flavor: { get_param: flavor }
          networks: ["port": {get_resource: port} ]
          name: { get_param: vm_name }
          block_device_mapping_v2:
          - device_name: vda
            volume_id: {get_resource: sys-vol}
            
    outputs:
      private_key:
        description: private key of created key pair
        value: { get_attr: [key, private_key] }
    
(A) 事前準備#
  • APIにて仮想サーバのフレーバー一覧を取得し、必要となるフレーバーのIDを控えてください。

    curl -Ss $COMPUTE/v2/$PROJECT_ID/flavors/detail -X GET -H "X-Auth-Token: $OS_AUTH_TOKEN" | jq '.flavors[] | {"name": .name, "vcpus": .vcpus, "ram": .ram, "id": .id,}'
    

  • APIにてイメージ一覧を取得し、必要となるOSのイメージIDを控えてください。

    curl $IMAGE/v2/images -X GET -H "X-Auth-Token: $OS_AUTH_TOKEN" | jq '.images[] | {"name": .name, "id":.id}'
    

(B) parametersセクション内の設定項目#

各パラメータの設定値は以下表の通りです。
必要に応じて修正ください。

パラメータ 設定値例                   説明                  
service_network1_name NW2 作成する仮想ネットワークの名前を指定
service_subnet1_name SN2 作成するサブネットの名前を指定
service_router1_name RT2 作成するルータの名前を指定
service_subnet1_cidr 192.168.2.0/24 作成するサブネットのCIDRを指定
service_subnet1_gw_ip 192.168.2.1 サブネットのゲートウェイIPを指定
service_subnet1_gw_port_name GWport2 サブネットのゲートウェイポートの名前を指定
security_group_name SG2 セキュリティグループの名前を指定
nameserver_ip1 8.8.8.8 サブネットに配備するサーバが使用するDNSサーバ1のIPアドレスを指定
nameserver_ip2 9.9.9.9 サブネットに配備するサーバが使用するDNSサーバ2のIPアドレスを指定
firewall1_policy_name FWpolicy2 ファイアーウォールポリシー名を指定
port_name Port2 作成する仮想サーバのポート名を指定
key_name Key2 作成するキーペア名を指定
ここで作成するキーペアが仮想マシンの作成時に使用される
image 1e8d4a48-bbde-416f-b6fd-fff016673d6c 仮想サーバの作成に使用するイメージIDを指定
volume_name Volume2 仮想サーバにアタッチさせるシステムストレージのボリューム名を指定
flavor fdbf1331-9dfe-4119-872d-3b88d1cb61b8 作成する仮想サーバのフレーバーIDを指定
vm_name VM2 作成する仮想サーバの名前を指定
(C) resourcesセクション内の設定項目#
  • セキュリティグループ
    以下のルールを保持するセキュリティグループが作成され、仮想サーバ(VM2)のポートに適用されます。
    必要に応じて修正ください。
ルール 方向 オープンポート ポート 接続先 セキュリティグループまたは CIDR IPバージョン
ALL ICMP 受信 - - CIDR 192.168.2.0/24 IPv4
カスタムTCPルール 受信 ポート 22 CIDR 192.168.2.0/24 IPv4
  • ファイアーウォール
    以下のファイアーウォールルールが作成され、ファイアーウォールポリシーとして仮想ルータ(RT2)に適用されます。
    必要に応じて修正ください。
no       名前       プロトコル IP
バージョン
アクション Srcアドレス Srcポート Destアドレス Destポート
1 *firewall_rule1* tcp 4 allow 192.168.2.0/24 null null 80
2 *firewall_rule2* udp 4 allow 192.168.2.0/24 53 8.8.8.8 null
3 *firewall_rule3* udp 4 allow 192.168.2.0/24 53 9.9.9.9 null
  • システムストレージ
    システムストレージ容量は60GBとなっています。
    必要に応じて修正ください。
(D) outputsセクション内の設定項目#

作成するキーペアの秘密鍵を出力します。
必要に応じて修正ください。

(2) スタックの作成#

IaaSポータルでは、以下の手順でスタックを作成します。

  • 「テンプレート」⇒「スタック」と選択した画面で、画面右上の「+」ボタンをクリックします。
  • 以下を入力して「作成」をクリックすると、「スタック」画面に戻り、スタックが "CREATE_IN_PROGRESS" というステータスで作成中になります。
項目 設定値例 説明
スタック名 sample_stack 任意のスタック名を指定
英数字と、"_"、"-"、"." のみ使用可。先頭文字は英字。
テンプレート
指定方法
YAML 以下よりテンプレートの指定方法を選択
  • URL
  • ファイル
  • YAML
  • テンプレート
    ファイル                                
    (上記のテンプレートの内容を編集したものをコピー/ペースト) テンプレートの指定方法に合わせて、項目名が以下のように変化
  • URL
  • ファイル
  • YAML
  • タイムアウト
    (分)
    10分 任意の値を入力
    失敗時のリソース削除                 「削除する」をチェックしない テンプレート実行失敗時に、失敗するまでに作成したリソースを削除する場合はチェックをする

    Note

    既存のセキュリティグループ数やセキュリティグループルール数との合計がプロジェクトの制限値を超える場合は、スタック作成が失敗するか、またはルールが一部作成されないで作成完了します。

    • しばらく時間をおいて、「スタック」画面をリロードします。
      スタックの作成が完了していると、ステータスが "CREATE_COMPLETE" となります。
      スタックの作成が失敗していると、ステータスが "CREATE_FAILED" となります。

    (3) スタックの確認#

    スタックが作成されたら、テンプレートの内容と実際の設定状況を照合して確認してください。

    Note

    スタックが "CREATE_COMPLETE" となっていても、セキュリティグループのルール数が制限値を超えていて、ルールが作成されていない場合があります。

    2. スタックの削除#

    (1) スタックの削除#

    IaaSポータルでは、以下の手順でスタックを削除します。

    • 「テンプレート」⇒「スタック」と選択した画面で、削除したいスタックの「アクション」メニューから、「削除」をクリックします。
    • 「スタック削除の確認」ウィンドウがポップアップされます。確認して「削除」をクリックします。
      「削除」クリックすると、「スタック」画面に戻り、"DELETE_IN_PROGRESS" というステータスで削除中になります。
    • しばらく時間をおいて、「スタック」画面をリロードします。
      スタックの削除が完了していると、スタックが一覧からなくなっています。
      スタックの削除が失敗していると、ステータスが "DELETE_FAILED" となります。

    Warning

    スタックを作成中に、スタックを削除しないでください。
    "DELETE_FAILED" となって、スタックが削除できなくなる可能性があります。

    メリット・効果#

    テンプレート配備 パターンを利用した場合のメリット・効果は以下の通りです。

    • 何度も利用する構成を定型化 (=テンプレート化) することにより、容易に、システムを一括で配備することが可能(自動化)
    • 開発/検証/本番等の環境等、同一の内容で環境を構築したい場合に、容易に、複数の環境を同じ内容で配備することが可能
    • テンプレートを流用したり再利用することで、構築コストを低減可能

    注意事項#

    • 本パターンは2020年6月時点のFJcloud-O 東日本/西日本リージョン3で動作検証しています。
    • 仕様により、外部ネットワークに接続させるルータの作成を含むテンプレートを使用してスタックを新規に作成することはできません。
      テンプレートにより作成したルータを外部ネットワークに接続させるには、IaaSポータルの「仮想ルータ一覧」画面より対象の仮想ルータの「アクション」⇒「編集」をクリックし、外部ネットワークとして「fip-net」を設定してください。
      その際には、必要に応じてセキュリティグループおよびファイアーウォールの設定を変更してください。
    • テンプレートのパラメータごとの詳細は HEATテンプレート解説書 でご確認ください。
      東日本/西日本リージョン3ではテンプレートの仕様が一部異なります。詳細は こちら を参照ください。
    • テンプレートに設定したパラメータがプロジェクトの制限値を超えている場合は、スタック作成が失敗したり、スタック作成が完了していても不備が出たりする場合があります。