プライベートサブネットでAnsibleを使う

プライベートサブネットでAnsibleを使う。

プライベートサブネット内のインスタンスにAWS-ApplyAnsiblePlaybooksドキュメントを実行する構成

以下のページで、EC2インスタンス(Amazon Linux 2)で初期化処理を実行する方法を4つご紹介しました。

あわせて読みたい
Linuxインスタンスの初期化方法4選 【Linuxインスタンスを初期化する4つの方法】 EC2インスタンスの起動時に初期化処理を実行する方法を考えます。 EC2インスタンスを構築時に初期化する以下の4つの手法を...

今回はその中の、Ansibleを使用する方法を掘り下げます。前述のページでは、インスタンスがパブリックサブネットに設置されている構成でした。今回はインスタンスがプライベートサブネット内に設置されている構成で、AWS-ApplyAnsiblePlaybooksドキュメントを実行する方法について取り上げます。以下の2つのパターンをご紹介します。

  • NATゲートウェイを使用するパターン
  • VPCエンドポイントを使用するパターン

構築する環境

Diagram of Ansible on Private Subnet.

EC2インスタンス①はNATゲートウェイを経由してAnsibleを実行するパターンです。EC2インスタンス②はVPCエンドポイントを経由してAnsibleを実行するパターンです。両インスタンスで実行するPlaybookは共通で、S3バケットに設置します。Playbookの内容ですが、Apacheをインストールし、動作させるものとします。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。以下のURLにCloudFormationテンプレートを配置してます。

https://github.com/awstut-an-r/awstut-fa/tree/main/025

テンプレートファイルのポイント解説

本ページでは、AWS-ApplyAnsiblePlaybooksドキュメント関係のリソースのみ解説します。AWS-ApplyAnsiblePlaybooksドキュメント実行に関する基本的な事項や、NATゲートウェイ用の設定、プライベートサブネット内でyumを実行する方法については、以下のページをご確認ください。

あわせて読みたい
Linuxインスタンスの初期化方法4選 【Linuxインスタンスを初期化する4つの方法】 EC2インスタンスの起動時に初期化処理を実行する方法を考えます。 EC2インスタンスを構築時に初期化する以下の4つの手法を...
あわせて読みたい
プライベートサブネットのインスタンスでyum/dnfを実行する 【プライベートサブネット内のインスタンスでyum/dnfを実行する構成】 プライベートサブネット内のインスタンスで、yum/dnfを実行する方法を確認します。 今回は以下の2...

AWS-ApplyAnsiblePlaybooksドキュメント実行①(NATゲートウェイ経由)

まずNATゲートウェイ経由でAWS-ApplyAnsiblePlaybooksドキュメントを実行するための設定を確認します。fa-025-ssm.yamlでSSM関係のリソースを定義しています。

Resources:
  ApplyAnsiblePlaybooksAssociation1:
    Type: AWS::SSM::Association
    DependsOn:
      - RunShellScriptAssociation
    Properties:
      AssociationName: !Sub ${Prefix}-apply-ansible-playbook-association1
      Name: AWS-ApplyAnsiblePlaybooks
      OutputLocation:
        S3Location:
          OutputS3BucketName: !Ref PlaybookBucket
          OutputS3KeyPrefix: !Sub "${Prefix}/playbook-association-log"
      Parameters:
        Check:
          - "False"
        ExtraVariables:
          - SSM=True
        InstallDependencies:
          - "True"
        PlaybookFile:
          - !Ref PlaybookFileName
        SourceInfo:
          - !Sub '{"path": "https://${PlaybookBucket}.s3.${AWS::Region}.amazonaws.com/${Prefix}/${PlaybookPackageName}"}'
        SourceType:
          - S3
        Verbose:
          - -v
      Targets:
        - Key: InstanceIds
          Values:
            - !Ref Instance1
      WaitForSuccessTimeoutSeconds: !Ref WaitForSuccessTimeoutSeconds
Code language: YAML (yaml)

先述のパブリックサブネットにインスタンスが設置されている場合の設定と同様です。今回はプライベートサブネット内にインスタンスは設置されていますが、NATゲートウェイを経由して、インターネットにアクセス可能であるため、パブリックサブネットの場合と同様の設定で動作します。

今回の構成において、特に注目な設定は、InstallDependenciesプロパティです。このオプションはAWS-ApplyAnsiblePlaybooksドキュメントを実行する上で、依存関係にあるパッケージをインストールするためのオプションです。そもそもデフォルトのAmazon Linux 2では、Ansibleはインストールされていません。ですから本オプションを有効化し、ドキュメント実行時にAnsibleをインストールさせます。

AWS-ApplyAnsiblePlaybooksドキュメント実行②(VPCエンドポイント経由)

続いてVPCエンドポイント経由でAWS-ApplyAnsiblePlaybooksドキュメントを実行するための設定を確認します。今回は以下の2つのリソースを作成します。

  • AWS-RunShellScript:Ansibleをインストールするために実行する。
  • AWS-ApplyAnsiblePlaybooks:Ansible Playbookの内容を実行する。

処理を2つのドキュメントに分けて定義した理由は、インスタンスがプライベートサブネットに設置されているため、先述のオプションを使ってでは、正常にAnsibleをインストールすることができないためです。これはインスタンスがプライベートサブネット上にあるため、インターネット向けに自由な通信ができないことに起因します。その事象のワークアラウンドとして、先にAWS-RunShellScriptドキュメントでAnsibleをインストールした後に、AWS-ApplyAnsiblePlaybooksドキュメントを実行することで対処します。

AWS-RunShellScript

Resources:
  RunShellScriptAssociation:
    Type: AWS::SSM::Association
    Properties:
      AssociationName: !Sub ${Prefix}-run-shellscript-association
      Name: AWS-RunShellScript
      OutputLocation:
        S3Location:
          OutputS3BucketName: !Ref PlaybookBucket
          OutputS3KeyPrefix: !Sub "${Prefix}/shellscript-association-log"
      Parameters:
        commands:
          - "sudo amazon-linux-extras install -y ansible2"
      Targets:
        - Key: InstanceIds
          Values:
            - !Ref Instance2
      WaitForSuccessTimeoutSeconds: !Ref WaitForSuccessTimeoutSeconds
Code language: YAML (yaml)

commandsプロパティでAnsibleインストール用コマンドを実行します。今回はAmazon Linux Extrasを使用してインストールします。

Extras は、安定したオペレーティングシステムで新しいバージョンのアプリケーションソフトウェアを利用可能にする Amazon Linux 2 のメカニズムで、2023 年 6 月 30 日までサポートされます。 (中略) Extras の例には、Ansible 2.4.2、memcached 1.5、nginx 1.12、Postgresql 9.6、MariaDB 10.2、Go 1.9、Redis 4.0、R 3.4、Rust 1.22.1 などがあります。

Amazon Linux Extras

AWS-ApplyAnsiblePlaybooks

Resources:
  ApplyAnsiblePlaybooksAssociation2:
    Type: AWS::SSM::Association
    DependsOn:
      - RunShellScriptAssociation
    Properties:
      AssociationName: !Sub ${Prefix}-apply-ansible-playbook-association2
      Name: AWS-ApplyAnsiblePlaybooks
      OutputLocation:
        S3Location:
          OutputS3BucketName: !Ref PlaybookBucket
          OutputS3KeyPrefix: !Sub "${Prefix}/playbook-association-log"
      Parameters:
        Check:
          - "False"
        ExtraVariables:
          - SSM=True
        InstallDependencies:
          #- "True"
          - "False"
        PlaybookFile:
          - !Ref PlaybookFileName
        SourceInfo:
          - !Sub '{"path": "https://${PlaybookBucket}.s3.${AWS::Region}.amazonaws.com/${Prefix}/${PlaybookPackageName}"}'
        SourceType:
          - S3
        Verbose:
          - -v
      Targets:
        - Key: InstanceIds
          Values:
            - !Ref Instance2
      WaitForSuccessTimeoutSeconds: !Ref WaitForSuccessTimeoutSeconds
Code language: YAML (yaml)

InstallDependenciesプロパティに注目してください。「False」を指定します。これは既にAWS-RunShellScriptドキュメントを実行してAnsibleをインストールしているため、依存関係の解決を図る必要がないためです。

(参考) Ansible Playbook

参考までに、今回実行するPlaybookの中身をご紹介します。

- hosts: all
  gather_facts: no
  become: yes

  tasks:
    - name: update yum
      yum: name=*
    - name: install the latest version of Apache
      yum: name=httpd state=latest
    - name: start and enable Apache
      service: name=httpd state=started enabled=yes
    - name: make index.html
      shell: ec2-metadata -i > /var/www/html/index.html
Code language: YAML (yaml)

Apacheをインストール後、インスタンスIDをindex.htmlに書き込むという内容です。今回はこの1つのPlaybookに、NATゲートウェイ経由と、VPCエンドポイント経由でアクセスして実行することになります。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

Ansible Playbookの準備

CloudFormationスタックを作成する前に、Ansibleの準備を行います。具体的にはPlaybookをZip化し、S3バケットに設置します。具体的なコマンドは先述のページをご確認ください。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

あわせて読みたい
CloudFormationのネストされたスタックで環境を構築する 【CloudFormationのネストされたスタックで環境を構築する方法】 CloudFormationにおけるネストされたスタックを検証します。 CloudFormationでは、スタックをネストす...

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • Instance1:i-0a2d78121ee6dfd1f
  • Instance2:i-057dde56603eebcf4

AWS Management Consoleからも、リソースの作成状況を確認します。まずEC2インスタンスを確認します。

The two instances have been created successfully.

2つのインスタンスが作成されていることがわかります。次にSSM State ManagerでSSMドキュメントの実行状況を確認します。

The SSM Association has been successfully created for the two instances.

2つのインスタンスに対して、合計3つの関連付けが作成されています。Statusが「Success」とありますので、正常に実行されたことがわかります。

動作確認①

準備が整いましので、インスタンスにアクセスします。まずインスタンス①です。インスタンスへのアクセスはSSM Session Managerを使用します。詳細については以下のページをご確認ください。

あわせて読みたい
LinuxインスタンスにSSM Session Manager経由でアクセスする 【LinuxインスタンスにSSM Session Manager経由でアクセスする】 EC2インスタンスにSSM Session Manager経由でアクセスする構成を確認します。 Session Manager は完全...
% aws ssm start-session --target i-0a2d78121ee6dfd1f

Starting session with SessionId: root-0f62c0c5edc7d8e07

sh-4.2$ 
Code language: Bash (bash)

curlで自分自身にアクセスします。

sh-4.2$ curl http://localhost
instance-id: i-0a2d78121ee6dfd1f
Code language: Bash (bash)

自分のIDが返ってきました。Ansible Playbookの内容が正常に実行されてたことがわかります。

参考に、以下がPlaybook実行時のログの抜粋です。

Amazon Linux release 2 (Karoo)

...

Installed:
  epel-release.noarch 0:7-14

...

Installed:
  ansible.noarch 0:2.9.27-1.el7

...

PLAY [all] *********************************************************************

TASK [update yum] **************************************************************
...

TASK [install the latest version of Apache] ************************************
...

TASK [start and enable Apache] *************************************************
...

TASK [make index.html] *********************************************************
...

PLAY RECAP *********************************************************************
localhost                  : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
Code language: plaintext (plaintext)

Playbookの内容を実行する前に、依存関係を解決するために、Ansibleをインストールしていることがわかります。

動作確認②

次にインスタンス②です。

% aws ssm start-session --target i-057dde56603eebcf4

Starting session with SessionId: root-083a1d2a50de3e64a

sh-4.2$

sh-4.2$ curl http://localhost
instance-id: i-057dde56603eebcf4
Code language: Bash (bash)

こちらも自身のIDが返ってきましたので、Ansible Playbookの内容が正常に実行されてたことがわかります。

こちらも実行時のログを確認します。まずAWS-RunShellScriptのログです。

Loaded plugins: extras_suggestions, langpacks, priorities, update-motd

...

Installed:
  ansible.noarch 0:2.9.23-1.amzn2

...

Complete!
Code language: plaintext (plaintext)

テンプレートファイルで指定した通り、Ansibleをインストールしています。次にAWS-ApplyAnsiblePlaybooksのログです。

PLAY [all] *********************************************************************

TASK [update yum] **************************************************************
...

TASK [install the latest version of Apache] ************************************
...

TASK [start and enable Apache] *************************************************
...

TASK [make index.html] *********************************************************
...

PLAY RECAP *********************************************************************
localhost                  : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
Code language: plaintext (plaintext)

こちらはAnsibleはインストールせず、最初からPlaybookを実行しています。

まとめ

プライベートサブネット内でAWS-ApplyAnsiblePlaybooksドキュメントを実行する方法を確認しました。具体的には、NATゲートウェイか、あるいはVPCエンドポイントを使用しました。