どこにでもいる30代SEの学習ブログ

主にプログラミング関連の学習内容。読んだ本の感想や株式投資についても書いてます。

【AWS】CloudFormationでHaskellの開発環境構築

f:id:predora005:20200920001147p:plain

※ 2019/02/24にQrunchで書いた記事を移行しました。

AWSのCloudFormationを使って、Haskellの開発環境を構築しました。

きっかけ

会社の先輩が最近"Haskell"にハマっていて、”Haskell"の良さを定期的にプレゼンされています(笑)。 色々説明してもらったのですが実際に書いてみないことには分からないことも多いので、ひとまず書いてみることにしました。

やったこと

f:id:predora005:20200919145437p:plain

手順

  1. CloudFormationのテンプレート作成
  2. マネージメントコンソールからスタック作成
  3. Haskell Stackを手動でアップグレード
  4. Haskellが動くことを確認

Haskell Stackのインストールがcfnヘルパーのみでは上手く行えなかったため、手順3を追加しました。 公式 の手順通りにやるとインストールは出来るのですがビルドが出来ませんでした。 下記を参考にしたら何とか動くようになりました。

EC2 user data script to install Haskell stack on Amazon Linux in order to build executables for AWS Lambda.

CentOSでHaskellプログラミング始め

[1] CloudFormationのテンプレートファイル作成

CloudFormationの概略は以前Qiitaにまとめました。

AWS CloudFormationでNAT構成を構築

[1-1] 構成

前回とは異なり、インスタンス1台の簡単な構成にしました。

[1-2] cfnヘルパーを使う

cfnヘルパーは、インスタンスにソフトウェアをインストール、サービス開始等々を行えるツールです。 インスタンス作成後に下記を行います。

  • stack, gitをインストール
  • GitHubからソースを取得

CloudFormation ヘルパースクリプトリファレンス - AWS CloudFormation

[1-3] UserDataプロパティ

UserDataプロパティに、インスタンス作成後に実行するシェルスクリプトを書きます。 大体テンプレートのコメント通りですが、

  • (2)でHaskell Stackをインストールします。
  • (3)でcfnヘルパーをインストールして(4)で使用します。
  • (4)でgitをインストールします。詳細はMetaDataプロパティに記載します。
  • (5)でGitHubからソースを取得します。
  • (6)はエラーハンドリング処理です。失敗するとロールバックしてくれます。
  MyInstance:
    Properties:
      UserData: !Base64
        Fn::Sub: |
          #!/bin/bash

          # (1) ソフトウェアの更新
          yum -y update

          # (2) Haskell Stackインストール用にリポジトリを追加
          curl -sSL 'https://s3.amazonaws.com/download.fpcomplete.com/centos/7/fpco.repo' | sudo tee /etc/yum.repos.d/fpco.repo

          # (3) cfnヘルパーをインストール
          yum -y install aws-cfn-bootstrap

          # (4) MetaDataプロパティに書かれたリソースをインストールしたり初期化
          /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource Instance --region ${AWS::Region}
          
          # (5) GitHubからHaskell用のファイルを取得
          cd /home/ec2-user/
          git clone 'https://github.com/predora005/haskell.git'
          chown ec2-user:ec2-user -R haskell/

          # (6) インスタンスが正常に作成されたかを通知する
          /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource Instance --region ${AWS::Region} 

[1-4] MetaDataプロパティ

cfnヘルパーでインストールするパッケージやファイルを、MetaDataプロパティに記載します。

  • yumでstack, git, treeをインストールします。
  • Haskell Stackアップグレード用のシェルスクリプトを作成します。 (アップグレードがcfnヘルパーでは環境変数やユーザー等の関係で上手くいかなかったためです)
  Instance:
    Type: 'AWS::EC2::Instance'
    Metadata:
      AWS::CloudFormation::Init:
        config:
          # パッケージのインストール
          packages:
            yum:
              stack: []
              git: []
              tree: []
          # ファイルの作成
          files: 
            '/home/ec2-user/upgrade_haskell.sh':
              content:
                Fn::Sub: |
                  #!/bin/bash
                  
                  # Haskell Stack update & upgrade
                  stack update
                  stack upgrade

                  # PATHにHaskell Stackのインストール先を追加
                  echo "export PATH=~/.local/bin:$PATH" >> /home/ec2-user/.bashrc
                  
              mode: "000644"
              owner: 'ec2-user'
              group: 'ec2-user'

[2] マネージメントコンソールからスタック作成

S3にテンプレートをアップロードし、マネージメントコンソールからスタックの作成を行います。

[3] Haskell Stackを手動でアップグレード

[3-1] EC2にログイン

ssh -i ./~~~.pem ec2-user@${IPアドレス}

[3-2] Haskell Stackをアップグレード

cfnヘルパーで作成したシェルスクリプトを実行します。

sh upgrade_haskell.sh
source ~/.bashrc

[4] Haskellが動くことを確認

cfnヘルパーでGitHubからcloneしたソースを動かします。

cd haskell/start-project
stack setup
stack build
stack exec start-project-exe

実際にやってみて

cfnヘルパーの動作確認に思ったように時間がかかりました。 スタック作成が終わるまでに数分かかるので、何度も動作確認を繰り返すとそれなりに時間を食います。

VPC, Subnet, IAMといった、ネットワークやAWSの設定関係はCloudFormationを使うメリットを感じましたが、cfnヘルパーについては少し使いづらい感もありました。 デプロイ関係はOpsWorksを使うのがよいのかもしれません。

特に今回は、Haskell Stackが公式通りの手順でインストールして動かなかった件の調査にも時間がかかってしまいました。

トラブルシューティング

  • cfn-initが上手くいかないときはログを確認する

    /var/log/cloud-init.log /var/log/cloud-init-output.log

  • cfnヘルパーはrootユーザーで実行される