CodeStarバンザイ!数クリックで始めるCI/CDパイプライン

CodeStarを使ってCI/CDパイプラインを構築してみたので、紹介します。

CodeStarとは?

AWSのマネージドサービスであるCodePipeline、CodeCommit、CodeBuild、CodeDeployを使ってCI/CDパイプライン+実行環境をさくっと構築してくれるサービスらしい。

https://aws.amazon.com/jp/codestar/

よしっ、動かしてみるぞ!!

1.プロジェクト作成

マネジメントコンソールからCodeStarを選び、「start a project」をポチッ。
するとプロジェクトのテンプレートを選択する画面が表示される。

カテゴリは、Web application、Web service、Alexa Skill、Static Websiteから、
言語は、Ruby、Node.js、Java、Python、PHP、HTML 5から、
実行環境は、Beanstalk、EC2、Lambdaから選択できる。
※もちろん存在しない組み合わせもあります。

今の時代っぽいWeb Application×Node.js×Lambdaなんてのも選択できるんですね。

うーん、ここはCodeBuildも使ってみたいし「Web Application×Java Spring×EC2」を選択。

使う1.png

そして、プロジェクト名を入力。インスタンスタイプを設定して。ポチッ、ポチッ。

使う2.png

。。。
はいっ、CI/CDパイプライン構築の作業はこれで終わり。

そして、待つこと10分。
CodePipeline、CodeCommit、CodeBuild、CodeDeployと、これを統合的に確認するためのダッシュボードがいい感じにできちゃいました。
もちろんjavaのwebアプリケーションも起動しています。

ダッシュボード

使う4修正.png

CodePipeline

使う8.png

CodeCommit

使う5.png

CodeBuild

使う6.png

CodeDeploy

使う7.png

デプロイされたjavaのwebアプリケーション

12.png

2.CI/CDパイプライン実行

ここからが本番。
gitへの接続情報をIAMで確認(ユーザ⇒認証情報⇒AWS CodeCommit の HTTPS Git 認証情報「生成」)し、code commit上のソースコードをcloneする。
するとこんなものが落ちてきます。

tree
.
├── README.md
├── appspec.yml
├── buildspec.yml
├── pom.xml
├── scripts
│   ├── install_dependencies
│   └── start_server
└── src
    └── main
        ├── java
        │   └── com
        │       └── aws
        │           └── codestar
        │               └── projecttemplates
        │                   ├── HelloWorldAppInitializer.java
        │                   ├── configuration
        │                   │   ├── ApplicationConfig.java
        │                   │   └── MvcConfig.java
        │                   └── controller
        │                       └── HelloWorldController.java
        ├── resources
        │   └── application.properties
        └── webapp
            ├── WEB-INF
            │   └── views
            │       └── index.jsp
            └── resources
                ├── gradients.css
                ├── set-background.js
                ├── styles.css
                └── tweet.svg

ふむふむ、なるほど。
ここは手っ取り早くCI/CDパイプラインを確認するため、index.jspをちょこっと修正。
そして、code commitにpush。
code commit上で、変更した内容も確認できます。

使う11.png
すると。。。

使う9.png

パイプラインが動き出したーーー
どうやら動きとしては、こんなことをやっているみたい。

  • Source : 新たしいコードがpushされると、code commitからソースコードを取得しS3に格納。
  • Build : S3からソースコードを取得しビルド。そしてビルドしたモジュールをS3に格納。
  • Application : S3に格納されたモジュールをEC2にデプロイ。

待つこと5分。デプロイまで成功。
そして、先程の画面を確認してみると。。。

使う10.png

変わった!
簡単!!

これを使えば

  • Java、Rubyなどメジャーな言語を利用したCI/CDパイプラインを爆速で構築できる。
  • Jenkinsから開放される。

がしかし。。

  • 東京リージョンにはまだ来ていない。
  • CodeStarというかcode commit側の問題になるが、pull requestが使えない。。

本番用のアプリケーション開発環境・実行環境として利用するのは、まだまだ難しいような気もしますが、
pocくらいであればこれで十分かもしれませんね。

続きを読む

AWS独学メモ

頑張って学んでいきます。

サービス俯瞰

コンピューティング関連

サービス名 概要
EC2 仮想サーバー
EC2 Container Service Doker(アプリ実行環境構築ツール)運用サービス
EC2 Container Regstry Dokerイメージ保存・共有サービス。
Elastic Beanstalk .NET/PHP/Python/Ruby/Node.jsアプリを自動でAWSにデプロイ。
Lambda クライアントからのリクエスト発生時に任意プログラミング起動。イベント駆動型サービス。
Auto Scaling CPU使用率等、事前決定条件に応じ、EC2インスタンス増減
Elastic Load Balancing トラフィックに応じ、複数EC2インスタンスに負荷分散

ストレージ・コンテンツ配信

サービス名 概要
S3 ファイルサーバ。画像格納したり。
CloudFront コンテンツ配信ネットワーク。利用者から近い場所から効率よく配信
EBS EC2データを保持するストレージ。EC2のHDD,SSDのような役割。
Elastic File System EC2共有ファイルストレージ
Glacier 低価格ストレージ。仕様頻度低いけど長期保存のバックアップ用。
Import / Export Snowball ペタバイト級の大容量転送サービス。
Storage Gateway オンプレミスとAWSを接続

DB関連

サービス名 概要
RDS DB(MySQL/Oracle/SQL Server/PostgreSQL/Aurora)が利用できる
Database Migration Service 最小限停止時間でDBを移行。オンプレミスのDBサーバからの移行等に用いる
DynamoDB NoSQLデータベスサービス構築/運用。
ElastiCache クラウドでのメモり内キャッシュの管理サービス
Redshift ビッグデータを分析

ネットワーク

サービス名 概要
VPC プライベートネットワーク構築サービス。
Direct Connect オンプレミスのネットワークとAWSのVPCネットワークを直接接続。
Route 53 DNS(ドメイン名とIPアドレスを対応)

開発者用ツール

サービス名 概要
CodeCommit プライベートGit
CodeDeploy 開発アプリを実行環境に自動配置
CodePipeline 継続的デリバリ使用したアプリのリリース

開発ツール

サービス名 概要
CloudWatch AWSリソース監視サービス
CloudFormation テンプレート利用したリソースの作成と管理
CloudTrail ユーザアクティビティとAPI使用状況確認
Config リソースのイベントリ変更の追跡
OpsWorks Chef利用し操作の自動化
Service Catalog 標準化製品の作成と使用
Trusted Advisor パフォーマンスとせきゅりてぃの最適化

セキュリティ

サービス名 概要
IAM AWS認証
Directory Service Active Directoryのホスティングと管理
Inspector アプリのセキュリティ分析
CloudHSM 暗号鍵管理の専用ハードウェア
Key Management Service 暗号鍵作成と管理
WAF 攻撃から保護するファイアウォール

分析

サービス名 概要
EMR Hadoopフレームワーク
Data Pipeline オーケストレーションサービス
Kinesis リアルタイムストリーミングデータとの連携
Machine Learning 機械学習
QuickSight 高速ビジネスインテリジェンスサービス

モバイルサービス

サービス名 概要
Mobile Hub モバイルアプリの構築/テスト/監視
API Gateway RESTful APIの構築/管理
Cofnito ユーザID及びアプリデータの同期
Device Farm iOS/Android/FireOSアプリのテスト
Mobile Analytics アプリ分析の収集/表示/エクスポート
Mobile SDK モバイルソフトウェアの開発キット

アプリケーションサービス

サービス名 概要
AppStream ストリーミングサービス
CloudSearch マネージド型検索サービス
Elastic Transcorder メディアと動画変換
SES Eメール送受信
SNS プッシュ通知サービス
SQS メッセージキューサービス
SWF アプリ同士を連携ワークフローサービス

大企業向け

サービス名 概要
WorkSpaces クラウド上仮想デスクトップパソコンサービス
WorkMail セキュリティ保護、企業向けEメール及びカレンダー
WorkDocs ファイル共有サービス

S3について

用語

用語 意味
バケット データの入れ物
オブジェクト 格納ファイル

ステップ

  1. バケット作成
  2. オブジェクト格納

EC2について

用語

用語 意味
EC2 仮想サーバ。オンプレミスのWindowsサーバやUNIXサーバに相当。
インスタンス 1台の仮想サーバ
EBS(Elastic Block Store) サーバのHDDに相当する仮想ディスク
AMI(Amazon Machine Image) サーバにインストールするOSやミドルウェアやアプリのイメージ。新インスタンスを複数生成時、AMIを利用。
yum パッケージ管理システム
scp(secure copy) SSH機能を用いて、安全にファイル転送する

EC2にSSH接続した

参考ページ1
参考ページ2

ミドルウェアをインストール

yum更新
$ sudo yum -y update
httpdインストール
$ sudo yum  install -y httpd
httpd起動
$ sudo service httpd start
httpd自動起動を確認
$ sudo chkconfig --list httpd
httpd自動起動を設定
$ sudo chkconfig  httpd on
$ sudo chkconfig  httpd off

scp(コンテンツをアップロードする)

【現在ここで躓き中!】
→ 突破!!

参考ページ1

HTTPコンテンツをコピー

HTTPコンテンツのコピー

$ sudo cp /home/ec2-user/index.html /var/www/html/

【現在ここで躓き中!】index.htmlへアクセスできない

続きを読む

Fresh Install bitnami redmine stack on AWS, then migrate old data and database from old instance.

Fresh Install bitnami redmine stack on AWS, then migrate old data and database from old instance.

目的: Redmine のバージョンアップ と HTTPS化

ですが、新環境の構築手順のみやっていただければ新規構築手順としても使えます。

  • 前回書いた記事から1年ちょっと経過しました。
  • bitnami redmine stack AMI のバージョンも以下のように変化しました。(2017/06/21 現在)
    • Old version 3.2.1
    • New version 3.3.3
  • 前回は GUI でぽちぽち作成しましたが、今回は AWS CLI を中心に進めます。
  • ついでに前回書いてなかった HTTPS化 についても簡単に追記します。
  • 以下の AWS の機能を利用します。
    • Route53: ドメイン名取得、名前解決(DNS)
    • ACM(Amazon Certificate Manager): 証明書発行
    • ELB(Elastic Load Balancer): 本来は複数インスタンスをバランシングする用途に使うものですが今回は EC2 インスタンス 1台 をぶら下げ、ACM で取得した証明書を配布し外部との HTTPS通信 のために利用します。

注意と免責

  • 無料枠でない部分は料金が発生します。
  • データの正常な移行を保証するものではありません。

前提

  • 現環境が正常に動作していること。
  • 新環境を同一リージョン、同一VPC、同一サブネット内に新たにたてます。
    • インスタンス間のデータ転送を SCP で簡易に行いたいと思います。
    • 適宜セキュリティグループを解放してください。
  • aws cli version
% aws --version
aws-cli/1.11.47 Python/2.7.12 Darwin/16.6.0 botocore/1.5.10

段取り

  • 大まかに以下の順序で進めます
  1. Version 3.3.3 の AMI を使って EC2 インスタンスを起動
  2. Version 3.2.1 のデータバックアップ
    • Bitnami Redmine Stack の停止
    • MySQL Dump 取得
  3. Version 3.3.3 へのデータ復元
    • Bitnami Redmine Stack の停止
    • MySQL Dump 復元
    • Bitnami Redmine Stack の開始
  4. 動作確認

参考資料

作業手順

1. Newer Bitnami redmine stack インスタンス作成

以下の条件で作成します。

  • Common conditions

    • AMI: ami-15f98503
    • Type: t2.micro
    • Public IP: あり
  • User defined conditions
    • Region: N.Virginia
    • Subnet: subnet-bd809696
    • Security Group: sg-5b5b8f2a
    • Keypair: aws-n.virginia-default001
    • IAM Role: ec2-001
    • EBS: 20GB

WEB GUI から作るも良し、AWS CLI から作るも良し
以下コマンド実行例

set-env
KEY_NAME=aws-nvirginia-default001.pem
echo $KEY_NAME
check-ami
aws ec2 describe-images \
    --filters "Name=image-id,Values=ami-15f98503"
check-ami-name
aws ec2 describe-images \
    --filters "Name=image-id,Values=ami-15f98503" \
    | jq ".Images[].Name" \
    | grep --color redmine-3.3.3
create-instance
aws ec2 run-instances \
    --image-id ami-15f98503 \
    --count 1 \
    --instance-type t2.micro \
    --key-name aws-n.virginia-default001 \
    --security-group-ids sg-5b5b8f2a \
    --subnet-id subnet-bd809696 \
    --block-device-mappings "[{\"DeviceName\":\"/dev/sda1\",\"Ebs\":{\"VolumeSize\":20,\"DeleteOnTermination\":false}}]" \
    --iam-instance-profile Name=ec2-001 \
    --associate-public-ip-address
set-env
INSTANCE_ID=i-0f8d079eef9e5aeba
echo $INSTANCE_ID
add-name-tag-to-instance
aws ec2 create-tags --resources $INSTANCE_ID \
    --tags Key=Name,Value=redmine-3.3.3

注意書きにもありますが以下に表示される MySQL Database の root パスワードは初期起動時にしか表示されません。
このときに保管しておくか MySQL のお作法にしたがって変更しておいても良いでしょう

check-instance-created
aws ec2 describe-instances --filter "Name=instance-id,Values=$INSTANCE_ID"
wait-running-state
aws ec2 describe-instances \
    --filter "Name=instance-id,Values=$INSTANCE_ID" \
    | jq '.Reservations[].Instances[].State["Name"]'
get-redmine-password
aws ec2 get-console-output \
    --instance-id $INSTANCE_ID \
    | grep "Setting Bitnami application password to"
get-publicip
aws ec2 describe-instances \
    --filter "Name=instance-id,Values=$INSTANCE_ID" \
    | jq '.Reservations[].Instances[].NetworkInterfaces[].Association'
set-env
PUBLIC_IP=54.243.10.66
echo $PUBLIC_IP
site-check
curl -I http://$PUBLIC_IP/
HTTP/1.1 200 OK
(snip)
ssh-connect
ssh -i .ssh/$KEY_NAME bitnami@$PUBLIC_IP
first-login
bitnami@new-version-host:~$ sudo apt-get update -y
bitnami@new-version-host:~$ sudo apt-get upgrade -y
bitnami@new-version-host:~$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.5 LTS"
bitnami@new-version-host:~$ sudo ./stack/ctlscript.sh status
subversion already running
php-fpm already running
apache already running
mysql already running
bitnami@new-version-host:~$ sudo ./stack/ctlscript.sh help
usage: ./stack/ctlscript.sh help
       ./stack/ctlscript.sh (start|stop|restart|status)
       ./stack/ctlscript.sh (start|stop|restart|status) mysql
       ./stack/ctlscript.sh (start|stop|restart|status) php-fpm
       ./stack/ctlscript.sh (start|stop|restart|status) apache
       ./stack/ctlscript.sh (start|stop|restart|status) subversion

help       - this screen
start      - start the service(s)
stop       - stop  the service(s)
restart    - restart or start the service(s)
status     - show the status of the service(s)

2. 旧バージョンのバックアップ取得

login_to_oldversion
Welcome to Ubuntu 14.04.3 LTS (GNU/Linux 3.13.0-74-generic x86_64)
       ___ _ _                   _
      | _ |_) |_ _ _  __ _ _ __ (_)
      | _ \ |  _| ' \/ _` | '  \| |
      |___/_|\__|_|_|\__,_|_|_|_|_|

  *** Welcome to the Bitnami Redmine 3.2.0-1         ***
  *** Bitnami Wiki:   https://wiki.bitnami.com/      ***
  *** Bitnami Forums: https://community.bitnami.com/ ***
Last login: Sun May 29 07:33:45 2016 from xxx.xxx.xxx.xxx
bitnami@old-version-host:~$
check-status
bitnami@old-version-host:~$ sudo stack/ctlscript.sh status
subversion already running
php-fpm already running
apache already running
mysql already running
stop
bitnami@old-version-host:~$ sudo stack/ctlscript.sh stop
/opt/bitnami/subversion/scripts/ctl.sh : subversion stopped
Syntax OK
/opt/bitnami/apache2/scripts/ctl.sh : httpd stopped
/opt/bitnami/php/scripts/ctl.sh : php-fpm stopped
/opt/bitnami/mysql/scripts/ctl.sh : mysql stopped
start-mysql
bitnami@old-version-host:~$ sudo stack/ctlscript.sh start mysql
170621 10:04:34 mysqld_safe Logging to '/opt/bitnami/mysql/data/mysqld.log'.
170621 10:04:34 mysqld_safe Starting mysqld.bin daemon with databases from /opt/bitnami/mysql/data
/opt/bitnami/mysql/scripts/ctl.sh : mysql  started at port 3306
check-available-filesystem-space
bitnami@old-version-host:~$ df -h /
Filesystem                                              Size  Used Avail Use% Mounted on
/dev/disk/by-uuid/6cdd25df-8610-4f60-9fed-ec03ed643ceb  9.8G  2.7G  6.6G  29% /
load-env-setting
bitnami@old-version-host:~$ . stack/use_redmine
bitnami@old-version-host:~$ echo $BITNAMI_ROOT
/opt/bitnami
dump-mysql
bitnami@old-version-host:~$ mysqldump -u root -p bitnami_redmine > redmine_backup.sql
Enter password:
bitnami@old-version-host:~$ ls -ltrh
  • scp 準備

手元の作業PCから新Redmine環境へssh接続するときに使用した証明書(pem)ファイルを旧Redmine環境にも作成します。

  • 今回は作業PC上で cat で表示させておいて旧環境のコンソール上にコピペしました。
example
bitnami@old-version-host:~$ vi .ssh/aws-nvirginia-default001.pem
bitnami@old-version-host:~$ chmod 600 .ssh/aws-nvirginia-default001.pem
  • ファイル転送
file_transfer
bitnami@old-version-host:~$ scp -i .ssh/aws-nvirginia-default001.pem redmine_backup.sql <new-version-host-ipaddr>:~
  • 新バージョン側にファイルが届いているか確認
check-transfered-files
bitnami@new-version-host:~$ ls -alh redmine*

3. 新バージョンへの復元

stop-stack
bitnami@new-version-host:~$ sudo stack/ctlscript.sh status
subversion already running
php-fpm already running
apache already running
mysql already running

bitnami@new-version-host:~$ sudo stack/ctlscript.sh stop

/opt/bitnami/subversion/scripts/ctl.sh : subversion stopped
Syntax OK
/opt/bitnami/apache2/scripts/ctl.sh : httpd stopped
/opt/bitnami/php/scripts/ctl.sh : php-fpm stopped
/opt/bitnami/mysql/scripts/ctl.sh : mysql stopped
start-mysql
bitnami@new-version-host:~$ sudo stack/ctlscript.sh start mysql
initial-database
bitnami@new-version-host:~$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.35 MySQL Community Server (GPL)

(snip)

mysql> drop database bitnami_redmine;

mysql> create database bitnami_redmine;

mysql> grant all privileges on bitnami_redmine.* to 'bn_redmine'@'localhost' identified by 'DATAB
ASE_PASSWORD';

mysql> quit
restore-dumpfile
bitnami@new-version-host:~$ mysql -u root -p bitnami_redmine < redmine_backup.sql
Enter password:
bitnami@new-version-host:~$
edit-line-18
bitnami@new-version-host:~$ vi /opt/bitnami/apps/redmine/htdocs/config/database.yml

    18    password: "DATABASE_PASSWORD"
db-migrate
bitnami@new-version-host:~$ cd /opt/bitnami/apps/redmine/htdocs/
bitnami@new-version-host:/opt/bitnami/apps/redmine/htdocs$ ruby bin/rake db:migrate RAILS_ENV=production
bitnami@new-version-host:/opt/bitnami/apps/redmine/htdocs$ ruby bin/rake tmp:cache:clear
bitnami@new-version-host:/opt/bitnami/apps/redmine/htdocs$ ruby bin/rake tmp:sessions:clear
stack-restart
bitnami@new-version-host:/opt/bitnami/apps/redmine/htdocs$ cd
bitnami@new-version-host:~$ sudo stack/ctlscript.sh restart

bitnami@new-version-host:~$ exit
site-check
curl -I http://$PUBLIC_IP/
HTTP/1.1 200 OK
(snip)

ブラウザでも http://$PUBLIC_IP/ でアクセスして旧環境のユーザー名とパスワードでログイン出来ることを確認してください。

この時点で旧環境のインスタンスを停止させておいて良いでしょう。
いらないと判断した時に削除するなりしてください。

4. おまけ HTTPS化

  • 4-1. Route53 でドメイン名を取得してください

    • .net で 年額 11 USドル程度ですので実験用にひとつくらい維持しておくと便利
  • 4-2. Certificate Manager で証明書を取得します
    • コマンドでリクエストしてます
aws acm request-certificate --domain-name redmine.hogefuga.net
check-status-pending
aws acm describe-certificate \
    --certificate-arn "arn:aws:acm:us-east-1:942162428772:certificate/fdf099f9-ced7-4b97-a5dd-f85374d7d112" \
    | jq ".Certificate.Status"
"PENDING_VALIDATION"
  • 4-3. 承認する

    • ドメインに設定しているアドレスにメールが飛んできます
  • 4-4. ステータス確認
check-status-ISSUED
aws acm describe-certificate \
    --certificate-arn "arn:aws:acm:us-east-1:942162428772:certificate/fdf099f9-ced7-4b97-a5dd-f85374d7d112" \
    | jq ".Certificate.Status"
"ISSUED"
  • 4-5. Classic タイプの HTTPS ELB をつくる
example
aws elb create-load-balancer \
    --load-balancer-name redmine-elb1 \
    --listeners "Protocol=HTTPS,LoadBalancerPort=443,InstanceProtocol=HTTP,InstancePort=80,SSLCertificateId=arn:aws:acm:us-east-1:942162428772:certificate/fdf099f9-ced7-4b97-a5dd-f85374d7d112" \
    --availability-zones us-east-1a \
    --security-groups sg-3c90f343
  • 4-6. インスタンスをくっつける
example
aws elb register-instances-with-load-balancer \
    --load-balancer-name redmine-elb1 \
    --instances i-0f8d079eef9e5aeba
  • 4-7. State が InService になるまで待ちます
example
aws elb describe-instance-health \
    --load-balancer-name redmine-elb1
  • 4-8. DNS Name を確認する(4-10. で使います)
example
aws elb describe-load-balancers \
    --load-balancer-name redmine-elb1 \
  | jq ".LoadBalancerDescriptions[].DNSName"
  • 4-9. 今の設定を確認
example
aws route53 list-resource-record-sets \
    --hosted-zone-id Z3UG9LUEGNT0PE | jq .
  • 4-10. 投入用の JSON をつくる
example
vi change-resource-record-sets.json
example
{
  "Comment": "add CNAME for redmine.hogefuga.net",
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "redmine.hogefuga.net",
        "Type":"CNAME",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": <DNSName>
          }
        ]
      }
    }
  ]
}

4-11. 設定投入

example
aws route53 change-resource-record-sets \
    --hosted-zone-id Z3UG9LUEGNT0PE \
    --change-batch file://change-resource-record-sets.json

4-12. 設定確認

example
aws route53 list-resource-record-sets \
    --hosted-zone-id Z3UG9LUEGNT0PE

4-13. ブラウザ確認

https://redmine.hogefuga.net

4-14. EC2 インスタンスのセキュリティグループ再設定

  • グローバルの TCP:80 削除
  • サブネット内の TCP:80 許可
check
aws ec2 describe-security-groups --group-ids sg-b7d983c8
change
aws ec2 modify-instance-attribute \
    --instance-id i-0f8d079eef9e5aeba \
    --groups sg-b7d983c8

4-15. 再度ブラウザからアクセス可能か確認

続きを読む

AWSでExcelからPDF変換を行う

Excelの見た目のままPDFを作成するために、libreconvを使用してExcelからPDFへconvertをしてみた

環境

  • Amazon Linux
  • Ruby 2.3.0
  • Ruby on Rails 5.0.1

AWSにLibreOfficeをインストールする

$ sudo wget http://ftp.yz.yamagata-u.ac.jp/pub/tdf/libreoffice/stable/5.3.3/rpm/x86_64/LibreOffice_5.3.3_Linux_x86-64_rpm.tar.gz
$ tar xvzf LibreOffice_5.3.3_Linux_x86-64_rpm.tar.gz
$ cd LibreOffice_5.3.3.2_Linux_x86-64_rpm/
$ cd RPMS/
$ sudo yum install *.rpm
$ sudo yum install dbus-glib

gemのインストール

Gemfileに下記を追加
gem 'libreconv'

実装

  require 'libreconv'

  def convert_pdf
    Libreconv.convert('public/sample.xlsx', 'public/sample.pdf')
  end

出力されるpdfはxlsxで指定した印刷イメージで作成されるようだが、指定のフォントがない場合は、多少印刷イメージがずれることがある。
印刷イメージがずれる場合は適宜フォントをインストールする必要がある。

続きを読む

Rails + Capistrano + Unicorn である日 Gemfileが読み込めなくなった話

Railsアプリを Capistrano + Unicorn + nginxでデプロイができるようになって喜んでいたのですが
ある日いつもの bundle exec cap production deployは成功するが結果が反映されなくなった、、、

unicorn.log
I, [2017-06-18T07:25:00.381245 #18202]  INFO -- : executing ["/var/www/myapp/shared/bundle/ruby/2.4.0/bin/unicorn", "-c", "/var/www/myapp/current/config/unicorn/production.rb", "-E", "production", "-D", {11=>#<Kgio::UNIXServer:fd 11>}] (in /var/www/myapp/releases/20170618072435)
I, [2017-06-18T07:25:00.381795 #18202]  INFO -- : forked child re-executing...
/home/suppin/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.15.1/lib/bundler/definition.rb:31:in `build': /var/www/myapp/releases/20170606053023/Gemfile not found (Bundler::GemfileNotFound)

エラーを見に行ったところGemfileがないと言われていました・・・

解決方法

myapp/config/unicorn/production.rb に下記を追記してあげる。
(環境によってはパスが異なるかもしれません)

production.rb
before_exec do |server|
  ENV["BUNDLE_GEMFILE"] = File.join(File.expand_path("../../../../", __FILE__), "current", "Gemfile")
end

その後unicornを再起動

補足

capistranoを使っていて、いつものkill -9コマンドでpidを殺しにいくと自動デプロイするときに怒られる。なのでcurrent/tmp/pid/unicorn.pidとかのファイルを削除してあげる必要がある。

解決方法は
http://unlearned.hatenablog.com/entry/2014/03/10/230954
を参考にさせていただきました。ありがとうございます。

続きを読む

AWS 認定ソリューションアーキテクト – アソシエイト 合格までに勉強したこと

概要

AWS 認定試験には「これを勉強すればいいよ!」という教科書があるわけではないので、何を勉強したらいいか分からず困っている人も多いと思います。
なので、私の勉強記録を共有します。

勉強前のスペック

AWSの初級者です。
EC2インスタンス起動やEBSのスナップショット取得の経験があるくらいでした。

勉強方法概要

AWS活用本を一冊読んで、
あとはAWS クラウドサービス活用資料集にある BlackBelt のスライド(PDF)を淡々と読みました。

その後、模擬試験を受けて本試験を受験しました。

勉強方法詳細

少し前に買っていた以下の本を読みました。分かりやすいです。

Amazon Web Services 定番業務システム12パターン設計ガイド

BlackBelt

自分が読んだ資料に○を付けました。
また、模擬試験と本試験を受けた経験から、各資料の重要度を評価しました。
※当たり前ですが、読んでいない資料の重要度は評価していません。また、重要度の正確性も保証しません。

コンピューティング

資料 読んだ  重要度 
[Amazon EC2] 
[Amazon EC2] Windows
[Amazon EC2] HPC
[Amazon EC2] リザーブドインスタンス
[Amazon EC2] スポットインスタンス
[Amazon EC2] Instance Store & Elastic Block Store
[Amazon EC2] VMImport/Export
[Elastic Load Balancing]
[Elastic Load Balancing] ロードバランサと Socket 接続を使用したイベント通知サーバの負荷分散
[Elastic Load Balancing] ELBを評価するためのベストプラクティス
[Auto Scaling]
[Amazon EC2 Container Service]
[AWS Elastic Beanstalk]
[AWS Lambda]
[AWS Lambda] update
[Amazon Lightsail]
[AWS Batch]

ストレージ & コンテンツ配信

資料 読んだ  重要度 
[Amazon EBS]
[Amazon S3] 
[Amazon CloudFront]
[Amazon CloudFront] Flash Media Server on AWS
[Amazon CloudFront] CloudFront 上限緩和申請 計算方法&申請手順
[Amazon CloudFront] まだ間に合う! Amazon CloudFront で ATS 対応
[Amazon Glacier]
[Amazon Glacier] 機能編
[AWS Storage Gateway]
[Amazon Elastic File System]

データベース

資料 読んだ  重要度 
[Amazon RDS]
[Amazon RDS] Aurora
[Amazon DynamoDB]
[Amazon ElastiCache]
[Amazon ElastiCache] Redis QA資料
[Amazon Redshift] 
[Amazon Database Migration Service]

ネットワーキング

資料 読んだ  重要度 
[Amazon VPC]
[Amazon VPC] VPN接続設定 参考資料
[AWS Direct Connect] 
[Amazon Route53]

開発者用ツール

資料 読んだ  重要度 
[AWS CodeCommit]
[AWS CodeBuild]
[AWS CodeDeploy]
[AWS CodePipeline]
[AWS SDK]
[AWS SDK] Java & .NET
[AWS SDK] PHP & Ruby & Boto(Python) & Javascript in Node.js
[AWS SDK] AWS Client side SDK Android & iOS & Javascript
[AWS CLI]
[AWS AWS Tools for Windows Powershell]

管理ツール

資料 読んだ  重要度 
[Amazon CloudWatch]
[AWS CloudFormation]
[AWS CloudTrail]
[AWS Config]
[AWS OpsWorks] AWS OpsWorksのご紹介
[AWS OpsWorks]
[AWS OpsWorks] ハンズオン
[AWS Service Catalog]
[Trusted Advisor] AWS サポート & Trusted Advisor
[Amazon EC2 Systems Manager]

セキュリティ & アイデンティ

資料 読んだ  重要度 
[Identity and Access Management (IAM)] 
[AWS CloudHSM] CloudHSM & Key Management Service
[AWS Key Management Service]
[AWS Directory Service]
[Amazon Inspector]
[AWS WAF]
[AWS Certificate Manager]

分析

資料 読んだ  重要度 
[Amazon EMR(Elastic MapReduce)]
[AWS Data Pipeline]
[Amazon Elasticsearch Service] Amazon CloudSearch & Amazon Elasticsearch Service
[Amazon Kinesis]
[Amazon QuickSight]
[Amazon Athena]

AI

資料 読んだ  重要度 
[Amazon AI]]

IoT

資料 読んだ  重要度 
[AWS IoT]

ゲーム開発

資料 読んだ  重要度 
[Amazon Lumberyard]

モバイルサービス

資料 読んだ  重要度 
[Amazon Cognito]
[Amazon Cognito] Amazon Cognito update
[Amazon Cognito] Amazon Cognito / Amazon Mobile Analytics
[AWS Device Farm]
[Amazon Mobile Analytics] Amazon Cognito / Amazon Mobile Analytics
[Amazon SNS] Amazon SNS/SQS
[Amazon SNS] モバイルプッシュ通知
[Amazon Pinpoint]  

アプリケーションサービス

資料 読んだ  重要度 
[Amazon API Gateway] 
[Amazon AppStream]
[Amazon CloudSearch] Amazon CloudSearch & Amazon Elasticsearch Service
[Amazon Elastic Transcoder]
[Amazon SES]
[Amazon SES] Amazon SES-Easy DKIM 設定サポート資料
[Amazon SQS] Amazon SNS/SQS
[Amazon Simple Workflow Service (SWF)]

エンタープライズアプリケーション

資料 読んだ  重要度 
[Amazon WorkSpaces]
[Amazon WorkDocs]
[Amazon WorkMail]
[Amazon Chime]

その他

資料 読んだ  重要度 
[Cost Explorer]
[AWS Management Console]

補足

重要度の低い資料も読んだ方がいいです。
なぜなら、マネージドサービス自体がAWSの活用事例であり、それらを知ることでシステム設計の勘所が分かるようになるからです。
また、重要度の高い機能との連携についての記載があることもあり、理解が深まります。

続きを読む

イカれたバックアップシステムを紹介するぜ!

オンプレにあるバックアップデータをAWSに持っていくための基盤を用意する話

AWS側の基盤作り

AWSにデータをバックアップするための基盤が必要
色々やってみた結果、EC2インスタンスは必須で

  • LVMのSnapshotをデータソースにし気合でrsyncでバックアップする!!!
  • インスタンスは使い終わったら破棄したい
  • できるだけ運用コストがかからない構成を考える

SAの方に相談したところStep Functionsが使えるとのことで、
State Machineを定義しLambda Functionを7個くらい書く

  • sc1 volumeでコストを抑える

夜間しか使わないので、これで間に合えばOK

SFNと連携するActivityアプリケーションの開発

State Machineに対してget activity task APIでポーリングし、
トークンと前段のLambdaからインスタンス情報を受け取りバックアップを実行するシンプルなもの。

  • Rubyで実装しました
  • 長時間ポーリングするとタイムアウトしてしまう

必要な場合は、Net::ReadTimeout, Seahorse::Client::NetworkingErrorをrescueしてretryすることで
長時間ポーリングしていられる

バックアップ方法の変更と移行

  • Activityアプリケーションはchefで配布し、cronもセットできる

Activity名をホスト名などの固有値にしておくと明示的に書かなくて良いので楽

  • rsyncの場合、初回同期に膨大な時間がかかる

まずは適当なインスタンスを用意し、バックアップサーバーからインスタンスへある程度同期させておく

スライド

IMAGE

続きを読む

ssm put-parameterでvalueにURLを指定するとGETされる件

事象

CLIを使ってAWSのEC2 Systems Manager Parameter StoreにURLの文字列を格納しようとした場合に以下のようなエラーとなりました。どうやらパラメータURLに対してGETした結果を格納しようとしている様子です。コンソールから手で登録できれば良いのですが、なぜかKMSにある自前のキーを使いたい場合CLI経由で登録する必要があります。

実行したコマンド
aws ssm put-parameter --name test.url --value "https://*****.co.jp" --type SecureString --key-id "****" --region ap-northeast-1

結果
An error occurred (ValidationException) when calling the PutParameter operation: 1 validation error detected: Value '

<!DOCTYPE HTML>
<html lang="ja">
以下略
</html>

' at 'value' failed to satisfy constraint: Member must have length less than or equal to 4096

原因

CLIの仕様で”file://”, “fileb://”, “http://” 及び “https://” のプレフィックスが付いた場合は自動的にデータをロードしてしまうためです。今回の場合はリモートファイルのURLと判断されて中身を取得しにいってしまったというわけです。

解決法

上記の仕様を使ってURLの文字列をデータとしてロードさせてやればOKです。

url.txtにURLを書いて保存します。

url.txt
https://*****.co.jp

下記のコマンドを実行

aws ssm put-parameter --name test.url --value "file://url.txt" --type SecureString --key-id "****" --region ap-northeast-1

注意点

この方法で登録はできるのですが、パラメータを読み出した時に改行コードが末尾に付いてくるので注意しましょう。
現在私の環境ではRubyのSDKから読み出した時にいちいちchompしています。もっとエレガントな方法があるのだと思いますが、併せて機能改善も待たれるところです。

続きを読む

AWSでAuto Scaling + Capistranoでデプロイはしているが、ソースコードが更新されるたびにAMIを作り変える手順をちょっと楽にする

今回解決したい問題

現在CapistranoでAuto Scaling環境にデプロイしていますが、以下のような課題があります

  • Capistranoのデプロイ先のサーバが設定ファイルに直書きされている。Auto Scalingでスケールアウト・インするたびに書き直さなければいけない
  • ソースコードを更新するたびにAMIを作り直さなければいけない。それに付随してAuto Scalingの起動設定やAuto Scalingグループの設定変更が必要

上記を解決すれば、ソース更新後のデプロイがいつでも可能になり、スケールアウトしても最新のコードがインスタンスに反映されるようになります

環境

  • Bitbucket
  • Rails: 5.1.1
  • Ruby: 2.4.1
  • デプロイ系の各種Gem
    • capistrano (3.8.X)
    • capistrano-bundler (1.2.X)
    • capistrano-rails (1.1.X)
    • capistrano-rbenv (2.1.X)
    • capistrano3-delayed-job (1.7.X)
    • capistrano3-unicorn (0.2.X)
    • aws-sdk (2.9.29)

作業ログ

Auto Scalingされているインスタンスを自動で取得する設定

現在、config/deploy/環境.rbにデプロイ先がドメイン名とともに直書きされているので、aws-sdkを使ってAuto Scalingグループ名から取得できるようにします。

aws-sdkは設定を記述しない場合は、~/.aws/configなどから情報を取得するのですが、今回は特定ディレクトリ以下で異なるAWS設定を使いたいためdirenvで設定をわけます。

Railsアプリディレクトリ直下でdirenv edit .と実行し、以下の設定を記述します。xxxとyyyは各自変えてください。

export AWS_ACCESS_KEY_ID=xxx
export AWS_SECRET_ACCESS_KEY=yyy
export AWS_DEFAULT_REGION=ap-northeast-1
export AWS_DEFAULT_OUTPUT=json

次に、Capistrano側に変更を加えます。まずAWSのAuto Scalingグループからインスタンスの情報を取得するためにlib/capistrano/helpers/aws_utils.rbに以下の記述をします。なお、aws-sdkはGemfileに記載されているものとしてすすめます。

lib/capistrano/helpers/aws_utils.rb

require 'aws-sdk'

module AWSUtils
  def self.auto_scaling_dns_list(group_name)
    instances_of_as = auto_scaling_instances(group_name)

    instances_ids = instances_of_as.map(&:instance_id)
    instances_of_ec2 = instances_ids.map do |instance_id|
      Aws::EC2::Resource.new.instance(instance_id)
    end.sort_by { |v| [v.launch_time, v.id] }
    instances_of_ec2.map(&:public_dns_name)
  end

  def self.auto_scaling_instances(group_name)
    as = Aws::AutoScaling::Client.new
    instances_of_as = as.describe_auto_scaling_groups(
      auto_scaling_group_names: [group_name],
      max_records: 1
    ).auto_scaling_groups[0].instances

    return [] if instances_of_as.empty?
    instances_of_as
  end
end

次に、config/deploy/環境.rbに以下の記述を追記し、既存のserverの記述を削除します。
userやrolesなどは適宜かえてください。auto_scaling_dns_listで返ってくるリストは、インスタンス起動順にソートされているので必ず古いインタスンスでmigrationなどが実行されるようになっています。

config/deploy/環境.rbに追記

group_name = 'auto_scalning_test'
AWSUtils.auto_scaling_dns_list(group_name).each_with_index do |dns, i|
  roles = i.zero? ? %w[web app db] : %w[web app]
  server dns, user: 'ec2-user', roles: roles
end

最後にCapfileに以下の記述を追記し、deployスクリプトからAWSUtilsが使えるようにします

Capfile

Dir.glob('lib/capistrano/helpers/*.rb').each { |r| import r }

スケールアウトした際に最新のコードが適用されるようにする

以下のように解決します。以下増えたインスタンス自身が起動後に自動で行います。

  1. 最新ソースコードを特定のディレクトリにpullする
  2. 最新のソースコード上からlocalhost(自インスタンス)に向けてデプロイする

最初に、localhostにsshでログインできるようにします。~/.ssh/id_rsa~/.ssh/id_rsa.pubは存在している前提です。

~/.ssh/configに以下を追加

Host *
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
# 権限をかえる
chmod 400 ~/.ssh/config 

# ローカルホストに繋げれるか確かめる
ssh localhost

次に、ソースコードをpullできるためにはBitbucketに鍵が登録されている必要があります。~/.ssh/id_rsa.pubを以下のように追加します。

image.png

次に、特定ディレクトリ以下に最新ソースコードをcloneします。今回は、/home/ec2-user/deploy/プロジェクト名のフォルダにcloneしました。

インスタンスが新規作成されたときのユーザデータを作ります。Auto Scalingの起動設定を作成するときに以下のユーザデータを追記しておきます。
ユーザデータのログは/var/log/cloud-init-output.log/var/log/cloud-init.logに出力されるのでうまくスクリプトが起動できなければそちらをみてデバッグします。

#!/bin/bash -ex
su - ec2-user /home/ec2-user/bin/self-deploy.sh production

上記のユーザデータで実行される/home/ec2-user/bin/self-deploy.shは以下のスクリプトとなります。作成後、chmod 755 ~/bin/self-deploy.shで権限をかえておきます。

/home/ec2-user/bin/self-deploy.sh

#!/bin/bash

####################################
# /home/ec2-user/bin/self-deploy.sh
####################################

# path
app_path=/var/www/aws-rails-cap-autoscale/current
deploy_path=/home/ec2-user/deploy/aws-rails-cap-autoscale

# environment
rails_env=$1

# change directory
cd $deploy_path

#️ export $PATH
export PATH

# update rails app for deploy
echo "=== [${rails_env}] update rails app for deploy ==="
git fetch origin master
git reset --hard origin/master
echo ""

# bundle install for deploy
echo "=== [${rails_env}] bundle install for deploy ==="
bundle install --path vendor/bundle --without production staging --quiet -j8
echo ""

# self-deploy
echo "=== [${rails_env}] self-deploy to localhost ==="
bundle exec cap local_${rails_env} deploy
echo ""

Capistrano側にconfig/deploy/local_production.rbを以下のように記載します。

config/deploy/local_production.rb

server 'localhost', user: 'ec2-user', roles: %i[web app db]

set :stage, :production
set :rails_env, :production

最後に上記を適用した、EC2のAMIイメージを作成し、Auto Scalingを更新すればスケールアウト後に自動で最新コードが適用されます。

まとめ

今回の作業でデプロイが結構楽になりましたが、まだ以下のような、今後解決したい課題があるのでいずれやろうと思います。

  • デプロイするたびにbundlerが2回はしるのでやや時間がかかる。rsyncなどで踏み台サーバから更新する

参考

続きを読む

非公開のS3に期間限定でアップロードしてもらうためのシンプルな運用

S3は非常に便利かつ、そのセキュリティの高さからセキュアな用途にも使われつつあります。

一方でファイルの交換でDropboxやGoogleDriveを禁止しているところは依然として多いです。クリック一つで、世界中に公開されてしまうというのは、運用上のリスクとも言えそうです。

とはいえ、大容量のファイルを「受け取りたい」というだけのニーズに答えれないのも辛い。

想定するシナリオ

  • 自社はプライベートなS3バケットに向けた一時的なアップロード用のHTMLフォームを作成
  • 自社から取引先にアップロードフォームをメールで送信
  • 取引先は、アップロードフォームを開いてファイルをアップロード
  • 自社はプライベートなS3バケットからデータを取り出す

という流れです。

サンプルソース

前提事項として、AWSのアクセスキーとシークレットキーはの環境変数で設定しているものとします。AWSのアクセスキーなどは、切り替えまで考えると、環境変数で設定するのが一番手軽だと思います(ファイルだとどうしてもうっかりコミットしてしまう)

export AWS_ACCESS_KEY_ID=XXXX
export AWS_SECRET_ACCESS_KEY=XXXX
export AWS_DEFAULT_REGION=ap-northeast-1
uploadform.rb
require 'base64'
require 'openssl'
require 'digest/sha1'
require 'time'


# 各種設定
bucket_name = "バケット名" #必ず変える
upload_dir = "uploads/" #アップロード用ディレクトリは予め作っておく
redirect_url = "http://qiita.com/" #アップロードが完了した時のリダイレクト先
expiration = (Time.now + 60*60*24*7).utc.iso8601 # 1week
upload_max = 1024 * 1024 * 1024 #1G

#各種アップロードの制限をpolicyとして記載する
policy_document = <<EOS
{"expiration": "#{expiration}",
  "conditions": [ 
    {"bucket": "#{bucket_name}"}, 
    ["starts-with", "$key", "#{upload_dir}"],
    {"acl": "private"},
    {"success_action_redirect": "#{redirect_url}"},
    ["starts-with", "$Content-Type", ""],
    ["content-length-range", 0, #{upload_max}]
  ]
}
EOS

# policyに対してsignatureを生成することで、ユーザ側で設定を変更できないようにする
policy = Base64.encode64(policy_document).gsub("n","")
signature = Base64.encode64(
    OpenSSL::HMAC.digest(
        OpenSSL::Digest::Digest.new('sha1'), 
        ENV['AWS_SECRET_ACCESS_KEY'], policy)
    ).gsub("n","")

#アップロードフォームを作成(ポリシーとシグネチャもポストするからフォームのパラメータは変えれない)
html = <<EOS
<html>
  <head>
    <title>S3 POST Form</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>

  <body>
  一週間限定のアップロードフォームです。最大1Gまでアップロードできます。<br/>
  アップロードが終わったら担当者にご連絡ください
    <form action="https://#{bucket_name}.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
      <input type="hidden" name="key" value="uploads/${filename}">
      <input type="hidden" name="AWSAccessKeyId" value="#{ENV['AWS_ACCESS_KEY_ID']}">
      <input type="hidden" name="acl" value="private">
      <input type="hidden" name="success_action_redirect" value="#{redirect_url}">
      <input type="hidden" name="policy" value="#{policy}">
      <input type="hidden" name="signature" value="#{signature}">
      <input type="hidden" name="Content-Type" value="">
      <input name="file" type="file" style="margin:10px;">
      <br>
      <input type="submit" value="Upload" style="margin:10px;"> 
    </form>
  </body>
</html>
EOS

puts html

実行

$ ruby uploadform.rb > upload.html

SS 2017-06-04 11.14.07.png

解説

他の案

s3にはpresingedurlという仕組みもあり、オブジェクト単位で、期間限定URLを生成する仕組みがS3にはあります。aws cli からもpresingedurlは生成できるのですが、基本はGETリクエストです。つまり期間限定のダウンロードURLの生成が基本的な機能のです。

SDKを使えば、PUTリクエストに対するpresingedurlも生成できるのですが、先にファイル名まで指定しなくてはなりません。できればユーザがアップロードするファイル名でS3に保存したいです。そのあたりが扱いにくいです。

真のサーバーレス

Lambdaとかでサーバーレスのフォームを作るとかってのもあるし、JSだけで動くS3アップロードフォームの例もあるのですが、サーバーレスというからには、アップロード用の画面さえもWebサーバを用意したくない(これはただの意地)。httpで何かを公開するということ時点で、企業によっては、何らかのレビューを通らないと行けないケースは多いかと思います。

なので、ローカルのHTMLで完結したく、ローカルのHTMLだとJavaScriptが動かないケースもあり、JSなしアップロードフォームを都度作るという方式にしました。

参考URL

http://dev.classmethod.jp/cloud/aws-s3-direct-upload/

続きを読む