EC2-ローカル間でのファイル転送

3行で分かるあらすじ

  1. EC2内でエクスポートしたsqlファイルをローカルに転送させたかった。
  2. FileZillaでSFTPを使って転送しようとしたが、なぜかsqlファイルが表示されなかった。
  3. 表示されない原因調べるのも馬鹿らしいのでscpで転送した。

環境

ローカル:Mac
Amazon EC2:Amazon Linux

EC2 → ローカル 転送

scp -i [公開鍵ファイルのパス] [ユーザ名@ドメイン]:[送信元EC2ファイルパス] [転送先ローカルファイルパス]

#scp -i /keys/hoge.pem user@ec2-xxxx.com:/sqls/hoge.sql /Desktop

ローカル → EC2 転送

scp -i [公開鍵ファイルのパス] [送信元先ローカルファイルパス] [ユーザ名@ドメイン]:[転送先EC2ファイルパス]

#scp -i /keys/hoge.pem /Desktop/hoge.sql user@ec2-xxxx.com:/sqls

まとめ

エンジニアたるものGUIばかりに頼っていてはいけないな!な!(戒め)

続きを読む

AWSにDjango環境を構築する

versions

Python : 2.7
Django : 1.10

Environment

EC2インスタンス : Amazon Linux
WSGI : gunicorn
Proxy : nginx

install python packages

sudo yum update
sudo yum install gcc
sudo yum install python-devel
sudo yum install python-psycopg2
sudo yum install postgresql-devel
pip install -r requirements.txt

reverse proxy

sudo yum install nginx
sudo vi /etc/nginx/nginx.conf
  • nginx.confに追記 line : 49
location / {
    proxy_pass http://127.0.0.1:8000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

# http://mydomain/static/ をDjangoのsettings.pyでSTATIC_ROOTに指定したディレクトリへルーティング
location /static/ {
    autoindex on;
    alias   /usr/share/nginx/html/django-project-name/staticfiles/;
}
sudo chmod 777 -R /usr/share/nginx/html ※1
sudo service nginx restart
gunicorn django-project-name.wsgi -D

Memo

python manage.py runserver 0.0.0.0:8000  # 全てのホストアドレスからのアクセスを許可
python manage.py migrate
python manage.py createsuperuser

# 事前にsettings.pyにSTATIC_ROOTを設定する (defaultでは記載されていない)
python manage.py collectstatic  # STATIC_ROOTに指定したディレクトリに静的ファイルが生成される

※1 : このディレクトリ下にDjangoプロジェクトを設置
当初はSTATIC_ROOTに設定したディレクトリのシンボリックリンクのみをここに貼ったが
静的ファイルを読み込む際に403エラーが発生してしまうためプロジェクトごとこのディレクトリに設置
所有がrootのディレクトリに対して、パーミッションを777に設定してしまうのは多少疑問が残るところ

SSL証明書

証明書はAWS Certificate Managerで発行し、Elastic Load Balancerにインストール
ELBとEC2間の通信はhttpとなるが、ELBとEC2が同じリージョンにある場合セキュリティの問題はなさそう

続きを読む

[AWS] Terraform で EFS 作って、EC2 起動時にマウントさせておく

Terraform を使うと、EFS を作成して EC2 にマウントさせておくなんてことが簡単にできます。
Autoscaling 環境で Web ドキュメントルートを共有したい時とかに便利なんで、みんな使えばいいと思うよ。
なお、この記事の想定読者は AWS はダッシュボードからポチポチしてインスタンス立てたりしてるけど、そろそろインフラをコードで管理したいな。Terraform とか便利そうだねー使ってみたいねーって人です。
てわけで、単純に EC2 立ち上げても面白くないので EFS をマウントさせてみました。

そもそも、Terraform ってなんだ?って人は、以下のページとか参考になると思います。
Terraform簡易チュートリアル on AWS

実際の設定

Terraform は、特定のディレクトリ下にある拡張子が .tf なファイルを全部読み込んでいい感じにリソースを起動してくれます。なので、機能別に .tf 作成していってみましょう。

メイン設定

まず、メインの設定を作成。
プロバイダーとか、設定ファイル内で使用する変数とか設定していってみましょうか。

main.tf
# 今回のプロジェクト名
variable "project" {}
variable "domain" {}

# AWS リソースを起動するリージョンとかの情報
variable "region" { default = "us-west-2" }
variable "azs" {
    default {
        "a" = "us-west-2a"
        "b" = "us-west-2b"
        "c" = "us-west-2c"
    }
}

# AMI ID (Amazon Linux)
variable "ami" { 
    default {
        "us-west-2" = "ami-8ca83fec"
    }
}

# EC2 接続用の SSH 鍵の公開鍵
variable "ssh_public_key" {}

provider "aws" {
    region = "${var.region}"
}

variable で設定した値は tf ファイル内で ${var.region} のようにして参照可能です。
また、terraform の各種コマンドを実行する際に以下のようにパラメータとして変数を渡して上書きすることもできます。

$ terraform plan \
  -var 'project=example' \
  -var 'domain=example.com'

同じディレクトリ内に terraform.tfvars というファイルがあれば、それを読み込んで値が上書きされたりします。この辺の詳細は以下を参照してください。
Input Variables – Terraform by HashiCorp

provider "aws" は、aws を使いますよって宣言です。
以下のように アクセスキーを書いておくこともできますが、それやるとうっかり github とかに公開した時とかに切ない目にあうのでやめたほうが吉でしょう。

provider "aws" {
    access_key = "__ACCESS_KEY__"
    secret_key = "__SECRET_KEY__"
    region = "us-west-2"
}

環境変数 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY を読み込んでいい感じでやってくれるので、僕は direnv 使って作業ディレクトリ内で環境変数を変更することで対応してます。
(もちろん、この場合でも .gitignore.envrc を含めておいて間違って公開しないようにしないと切ない目にあうので注意)

VPC の作成

こんな感じの .tf ファイルで VPC と subnet が作成できます。

vpc.tf
## VPC
resource "aws_vpc" "app" {
    cidr_block           = "172.31.0.0/16"
    enable_dns_hostnames = true
    enable_dns_support   = true
    instance_tenancy     = "default"

    tags {
        "Name" = "${var.project}"
    }
}

## Subnet
resource "aws_subnet" "a" {
    vpc_id                  = "${aws_vpc.app.id}"
    cidr_block              = "172.31.0.0/20"
    availability_zone       = "${lookup(var.azs,"a")}"
    map_public_ip_on_launch = true

    tags {
        "Name" = "${var.project}-subnet-a"
    }
}

resource "aws_subnet" "b" {
    vpc_id                  = "${aws_vpc.app.id}"
    cidr_block              = "172.31.16.0/20"
    availability_zone       = "${lookup(var.azs,"b")}"
    map_public_ip_on_launch = true

    tags {
        "Name" = "${var.project}-subnet-b"
    }
}

resource "aws_subnet" "c" {
    vpc_id                  = "${aws_vpc.app.id}"
    cidr_block              = "172.31.32.0/20"
    availability_zone       = "${lookup(var.azs,"c")}"
    map_public_ip_on_launch = true

    tags {
        "Name" = "${var.project}-subnet-c"
    }
}

resource "aws_subnet" の中に ${aws_vpc.app.id} ってのが出てきましたね。
Terraform の中では、管理下にあるリソースの情報を他のリソースの設定でも参照することが可能です。
各リソースで使用できる値が異なってくるので、その辺は公式ドキュメント読みましょう。
例えば aws_vpc で使用できる値は aws_vpc を参照すればわかります。

また、${lookup(var.azs,"a")} ってのも出てきましたね。
これは Terraform の組み込み関数です、lookup は配列の中からキーをもとに値を探す関数です。
詳しくは Built-in Functions を読んでください。

ついでに Internet Gateway と Route Table も設定しておきましょう。

route-table.tf
## Internet Gateway
resource "aws_internet_gateway" "igw" {
    vpc_id = "${aws_vpc.app.id}"
}

## Route Table
resource "aws_route_table" "rtb" {
    vpc_id     = "${aws_vpc.app.id}"
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.igw.id}"
    }
}

resource "aws_route_table_association" "route_a" {
    subnet_id = "${aws_subnet.a.id}"
    route_table_id = "${aws_route_table.rtb.id}"
}

resource "aws_route_table_association" "route_b" {
    subnet_id = "${aws_subnet.b.id}"
    route_table_id = "${aws_route_table.rtb.id}"
}

resource "aws_route_table_association" "route_c" {
    subnet_id = "${aws_subnet.c.id}"
    route_table_id = "${aws_route_table.rtb.id}"
}

IAM ロールの作成

次に EC2 に割り当てるための IAM ロールを作ってみましょう。
ポリシーは、AWS が用意している AmazonEC2RoleforDataPipelineRole と、EC2 から CloudwatchLogs にログを送信するためのカスタムポリシーを作ってアタッチしてみます。

iam-role.tf
## For EC2 instance Role
resource "aws_iam_role" "instance_role" {
    name               = "instance_role"
    path               = "/"
    assume_role_policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
POLICY
}

## AmazonEC2RoleforDataPipelineRole
resource "aws_iam_role_policy_attachment" "data-pipeline" {
    role       = "${aws_iam_role.instance_role.name}"
    policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforDataPipelineRole"
}

## PutCloudwatchLogs
resource "aws_iam_policy" "put-cloudwatch-logs" {
    name        = "AmazonEC2PutCloudwatchLogs"
    description = ""
    policy      = <<POLICY
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}
POLICY
}

resource "aws_iam_role_policy_attachment" "put-cloudwatch-logs" {
    role       = "${aws_iam_role.instance_role.name}"
    policy_arn = "${aws_iam_policy.put-cloudwatch-logs.arn}"
}

aws_iam_roleassume_role_policy のところと、aws_iam_policypolicy のところでヒアドキュメントが出てきましたね。
こんな風に複数行にわたるインラインポリシーはヒアドキュメントで記述することが可能です。
また、以下のように別ファイルにしておいて読み込ませることも可能です。
管理しやすい方でやってください。

iam-role.tf
resource "aws_iam_role" "instance_role" {
    name               = "instance_role"
    path               = "/"
    assume_role_policy = "${file("data/instance_role_assume_policy.json")}"
}
data/instance_role_assume_policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

セキュリティグループの作成

EC2 から EFS へのアクセスは 2049 番ポートを介して行われるので、EFS が所属するセキュリティグループに穴を開けないといけません。
EC2 は 80, 443, 22 を解放してみます。

security-group.tf
## For EC2
resource "aws_security_group" "ec2" {
    name        = "${var.project}-EC2"
    description = "for ${var.project} EC2"
    vpc_id      = "${aws_vpc.app.id}"

    ingress = [
        {
            from_port       = 80
            to_port         = 80
            protocol        = "tcp"
            cidr_blocks     = ["0.0.0.0/0"]
        },
        {
            from_port       = 443
            to_port         = 443
            protocol        = "tcp"
            cidr_blocks     = ["0.0.0.0/0"]
        },
        {
            from_port       = 22
            to_port         = 22
            protocol        = "tcp"
            cidr_blocks     = ["0.0.0.0/0"]
        }
    ]

    egress {
        from_port       = 0
        to_port         = 0
        protocol        = "-1"
        cidr_blocks     = ["0.0.0.0/0"]
    }
}

## For EFS
resource "aws_security_group" "efs" {
    name        = "${var.project}-EFS"
    description = "for ${var.project} EFS"
    vpc_id      = "${aws_vpc.app.id}"

    ingress {
        from_port       = 2049
        to_port         = 2049
        protocol        = "tcp"
        security_groups = ["${aws_security_group.ec2.id}"]
    }

    egress {
        from_port       = 0
        to_port         = 0
        protocol        = "-1"
        cidr_blocks     = ["0.0.0.0/0"]
    }
}

EFS の作成

こんな感じで EFS が作成できます。
各サブネットごとにマウントターゲットを作成して、そいつをセキュリティグループに所属させる形ですね。

efs.tf
resource "aws_efs_file_system" "app" {
  tags {
        "Name" = "${var.domain}"
  }
}

resource "aws_efs_mount_target" "app-a" {
  file_system_id  = "${aws_efs_file_system.app.id}"
  subnet_id       = "${aws_subnet.a.id}"
  security_groups = ["${aws_security_group.efs.id}"]
}

resource "aws_efs_mount_target" "app-b" {
  file_system_id = "${aws_efs_file_system.app.id}"
  subnet_id      = "${aws_subnet.b.id}"
  security_groups = ["${aws_security_group.efs.id}"]
}

resource "aws_efs_mount_target" "app-c" {
  file_system_id = "${aws_efs_file_system.app.id}"
  subnet_id      = "${aws_subnet.c.id}"
  security_groups = ["${aws_security_group.efs.id}"]
}

EC2 の作成

さて、いよいよ EC2 です。
ここでは、user-data を使って、初回ローンチ時に EFS をマウントさせてしまいます。
さらにマウントした EFS 内に html/ ってディレクトリを作成して、そいつを /var/www/html にシンボリックリンクしてみましょうか。
と言っても、こんな感じで大丈夫です。

ec2.tf
## IAM Instance Profile
resource "aws_iam_instance_profile" "instance_role" {
    name = "instance_role"
    role = "${aws_iam_role.instance_role.name}"
}

## SSH Key
resource "aws_key_pair" "deployer" {
  key_name   = "${var.project}"
  public_key = "${var.ssh_public_key}"
}

## EC2
resource "aws_instance" "app" {
    ami                         = "${lookup(var.ami,var.region)}"
    availability_zone           = "${aws_subnet.a.availability_zone}"
    ebs_optimized               = false
    instance_type               = "t2.micro"
    monitoring                  = true
    key_name                    = "${aws_key_pair.deployer.key_name}"
    subnet_id                   = "${aws_subnet.a.id}"
    vpc_security_group_ids      = ["${aws_security_group.ec2.id}"]
    associate_public_ip_address = true
    source_dest_check           = true
    iam_instance_profile        = "${aws_iam_instance_profile.instance_role.id}"
    disable_api_termination     = false

    user_data                   = <<USERDATA
#!/bin/bash
az="${aws_subnet.a.availability_zone}"
efs_region="${var.region}"
efs_id="${aws_efs_file_system.app.id}"
efs_mount_target="${aws_efs_mount_target.app-a.dns_name}:/"
efs_mount_point="/mnt/efs/$${efs_id}/$${az}"
web_doc_root="/var/www/html"

# EFS Mount
/usr/bin/yum -y install nfs-utils || /usr/bin/yum -y update nfs-utils
if [ ! -d $${efs_mount_point} ]; then
  mkdir -p $${efs_mount_point}
fi
cp -pi /etc/fstab /etc/fstab.$(date "+%Y%m%d")
echo "$${efs_mount_target}    $${efs_mount_point}   nfs4    defaults" | tee -a /etc/fstab
mount $${efs_mount_point}

# create Web document root
if [ -d $${web_doc_root} ]; then
  rm -rf $${web_doc_root}
fi
if [ ! -d $${efs_mount_point}/html ]; then
  mkdir $${efs_mount_point}/html
  chown ec2-user:ec2-user $${efs_mount_point}/html
fi
ln -s $${efs_mount_point}/html $${web_doc_root}
chown -h ec2-user:ec2-user $${web_doc_root}
USERDATA

    root_block_device {
        volume_type           = "gp2"
        volume_size           = 10
        delete_on_termination = true
    }

    tags {
        "Name"          = "${var.domain}"
    }
}

user_data は長めのシェルスクリプトなので、可読性が悪いから ${file("data/user_data.sh")} とかってやって別ファイルで管理したいですよね。
でも待ってください、ヒアドキュメントでやってるのは理由があるのです。

ヒアドキュメントで書くと、user_data 用のシェルスクリプトの中で Terraform の変数が使えます。
マウントするには EFS の ID とか、マウントターゲットの dns_name とか必要になってきますが、それを作成前に知らなくてもこのように書いておけるのです。便利ですね。
その代わり、user_data 用のシェルスクリプト内でローカルな環境変数を使いたい場合は $${efs_mount_point} のように書いてあげてくださいね。

ざっと、こんな感じです。
慣れちゃえば、tf ファイルを使い回しできるので便利ですよ。
また、すでに作成済みの AWS リソースを Terraform 管理下に置きたい場合は

$ terraform import aws_instance.app ${instance_id}

のようにして管理下に置くことができます。
管理されているリソースは terraform.tfstate というファイルに書き込まれます。
さらに別プロダクトになるのですが Terraforming と言うツールを使用すると、既存の AWS リソースから Terraform 用の tf ファイルを作成したり、terraform.tfstate を作成したりもできるので便利です。
Terraforming については、Terraforming で既存のインフラを Terraform 管理下におく を参考にしてください。

実際にリソース作成してみる

tf ファイル書いたら

$ terraform plan

で、設定ファイルに誤りがないか?既存のリソースへの影響はどの程度あるのかが確認できます。
実際に反映させたい時は

$ terraform apply

で、おっけ。

では、良い Terraform を!

続きを読む

EC2をAnsibleで管理する

はじめに

AnsibleにはAWSのリソースを操作できるモジュールが豊富に用意されています。

今回は、定番のEC2をAnsibleで管理してみます。

やること

  • EC2インスタンス作成

ポイント

ec2モジュールは、セキュリティグループについては名前で指定できるのですが、サブネットはIDで指定する必要があります。

しかし、サブネットIDをAnsibleのYAMLに書きたくないので、サブネット名からIDを取得する実装とします。

前提

AWS関連のモジュール実行にはbotoが必要です。
credential情報は環境変数かaws configureでセットしてある必要があります。

下記リソースを前提に進めます。

  • VPC

    • AnsibleVPC
  • キーペア
    • keypair
  • サブネット
    • public-a
    • public-c
  • セキュリティグループ
    • common
    • web_server

sample

以下のようなEC2インスタンスを作成します。

  • testinstance1

    • AmazonLinux
    • アベイラビリティゾーンA
    • セキュリティグループ
      • common,web_server
  • testinstance2
    • AmazonLinux
    • アベイラビリティゾーンC
    • セキュリティグループ
      • common

ディレクトリ構成

ディレクトリ構成
site.yml
roles/
|--ec2/
|  |--tasks/
|  |  |--main.yml
hosts/aws    #inventory
host_vars/
|--localhost.yml

inventory

AWSリソース関連モジュールはすべてlocalhostで実行するので、下記のようなインベントリファイルを用意します。

hosts/aws
[aws]
localhost

vars

こんな感じに変数を定義します。今回はhost_varsで定義しました。

host_vars/localhost.yml
---
my_vars:
  aws:
    common:
      region: ap-northeast-1
    vpc:
      name: AnsibleVPC    # ターゲットのVPC名
    ec2:
      testinstance1:
        ami_image: ami-56d4ad31 # Amazon Linux
        key_name: keypair # キーペア名
        security_group:
          - common
          - web_server
        instance_type: t2.micro
        device_name: /dev/xvda
        device_type: gp2
        volume_size: 8 # EBSのディスクサイズ(GB)
        subnet: public-a # サブネット名
        assign_public_ip: yes
        tags:
          Name: testinstance1
          Role: test
      testinstance2:
        ami_image: ami-56d4ad31 # Amazon Linux
        key_name: keypair # キーペア名
        security_group:
          - common
        instance_type: t2.micro
        device_name: /dev/xvda
        device_type: gp2
        volume_size: 8 # EBSのディスクサイズ(GB)
        subnet: public-c # サブネット名
        assign_public_ip: yes
        tags:
          Name: testinstance2
          Role: test

Role

まずVPCを特定するためにidが必要ですが、こちらと同様、VPC名でidを取得します。

今回はリストではなくディクショナリとしてEC2インスタンスを定義しましたので、with_dictでループさせます。

前述のように、サブネットはIDで指定する必要があるので、ec2_vpc_subnet_factsモジュールでIDを取得します。

定義されたEC2インスタンスの全てのサブネット名とIDのディクショナリを作成し、後続taskで参照します。

あとはec2モジュールで作成しますが、exact_count: 1を指定することで重複作成を防止します(stop状態だと作成されてしまいますが)。

roles/vpc/tasks/main.yml
---
- name: vpc_id取得
  ec2_vpc_net_facts:
    region: "{{ my_vars.aws.common.region }}"
    filters:
      "tag:Name": "{{ my_vars.aws.vpc.name }}"
  register: vpc_net_fact

- debug: var=vpc_net_fact

- name: subnet id取得
  ec2_vpc_subnet_facts:
    region: "{{ my_vars.aws.common.region }}"
    filters:
      vpc_id: "{{ vpc_net_fact.vpcs[0].id }}"
      "tag:Name": "{{ item.value.subnet }}"
  with_dict: "{{ my_vars.aws.ec2 }}"
  register: subnet_fact
  when: my_vars.aws.ec2 is defined

- name: subnet dict作成
  set_fact:
    subnet_dict: >-
      {%- set dict = {} -%}
      {%- for i in range(subnet_fact.results|length) -%}
      {%-   set _ = dict.update({subnet_fact.results[i].subnets[0].tags.Name: subnet_fact.results[i].subnets[0].id}) -%}
      {%- endfor -%}
      {{ dict }}
  when: my_vars.aws.ec2 is defined

- name: EC2インスタンスを作成
  ec2:
    image: "{{ item.value.ami_image }}"
    instance_type: "{{ item.value.instance_type }}"
    region: "{{ my_vars.aws.common.region }}"
    key_name: "{{ item.value.key_name }}"
    group: "{{ item.value.security_group }}"
    vpc_subnet_id: >-
      {%- set id = subnet_dict[item.value.subnet] -%}
      {{ id }}
    instance_tags: "{{ item.value.tags }}"
    assign_public_ip: "{{ item.value.assign_public_ip }}"
    private_ip: "{{ item.value.private_ip }}"
    wait: yes
    wait_timeout: 300
    volumes:
      - device_name: "{{ item.value.device_name }}"
        device_type: "{{ item.value.device_type }}"
        volume_size: "{{ item.value.volume_size }}"
        delete_on_termination: true
    count_tag:
      Name: "{{ item.value.tags.Name }}"
    exact_count: 1
    user_data: |
      #!/bin/bash
      # 初期設定スクリプトなど
  with_dict: "{{ my_vars.aws.ec2 }}"
  register: ec2
  when: my_vars.aws.ec2 is defined

- debug: var=ec2

site.yml

site.yml
---
- name: ec2
  hosts: localhost
  connection: local
  roles:
    - role: ec2

実行

Command
$ ansible-playbook -i hosts/aws -l localhost site.yml

まとめ

ネット上のサンプルでもサブネットIDを指定している例がほとんどですが、実際YAMLで管理する場合、IDではなく名前の方が分かりやすいと思います。
参考になれば幸いです。

参考

続きを読む

Docker for Mac で Amazon Linuxのコンテナイメージを動かす

はじめに

macbook air をクリーンインストールしたついでに、開発環境をイチから構築していました。
Docker の コンテナイメージ何にしようかと探していたら Amazon Linuxがコンテナ化されていたんですね。
(今更しりました…。)
ということで、折角知ったので macで Amazon Linuxのコンテナを動かしてみます。

前準備

docker for mac のインストール

$ brew cask install docker
$ docker -v

Docker version 17.03.1-ce, build c6d412e

aws cli の インストール と 設定

$ brew install awscli
$ aws --version

aws-cli/1.11.76 Python/2.7.10 Darwin/16.5.0 botocore/1.5.39
$ aws configure

AWS Access Key ID [None]: `IAMのアクセスキー`
AWS Secret Access Key [None]: `上記IAMのシークレットキー`
Default region name [None]: ap-northeast-1
Default output format [None]: json

ここから本番

AmazonLinuxコンテナが配布されているECRへのログインコマンドを取得します。

$ aws ecr get-login --region ap-northeast-1 --registry-ids 137112412989
docker login -u AWS -p 'パスワード' -e none https://137112412989.dkr.ecr.ap-northeast-1.amazonaws.com

上記のコマンドが表示されるので、コピペして実行します。

Flag --email has been deprecated, will be removed in 1.14.
Login Succeeded

ログイン成功したようなので、イメージの種類を aws ecr list-imagesで確認してみます。

$ aws ecr list-images --region ap-northeast-1 --registry-id 137112412989 --repository-name amazonlinux | grep 'imageTag'

"imageTag": "2016.09.0.20161028-with-sources",
"imageTag": "2016.09.1.20161221",
"imageTag": "with-sources",
"imageTag": "2016.09.0.20161118",
"imageTag": "2016.09-with-sources",
"imageTag": "latest-with-sources",
"imageTag": "latest",
"imageTag": "2016.09.1.20161221-with-sources",
"imageTag": "2016.09",
"imageTag": "2016.09.0.20161118-with-sources",
"imageTag": "2016.09.0.20161028"

ここでは もちろん latestをローカルにpull してみます。

$ docker pull 137112412989.dkr.ecr.ap-northeast-1.amazonaws.com/amazonlinux:latest
$ docker images

REPOSITORY                                                      TAG                 IMAGE ID            CREATED             SIZE
137112412989.dkr.ecr.ap-northeast-1.amazonaws.com/amazonlinux   latest              ff59a593059d        3 months ago        292 MB

試しに実行してみます。 docker run

$ docker run -it 137112412989.dkr.ecr.ap-northeast-1.amazonaws.com/amazonlinux:latest /bin/bash

bash-4.2# cat /etc/system-release
Amazon Linux AMI release 2016.09

おお。できてますね!
必要最低限のパッケージしか入っていないみたいなので、次回はこれを使って環境構築をしていきます。

image

classmethodさんの記事に cawsayが載っていたので、真似してみました。:-)

SEE ALSO

続きを読む

AmazonLinuxにClamAVをインストールしちゃったよ

Amazon LinuxにClamAVをインストール方法について記載しますー

環境

  • InstanceType:t2.medium
  • OS:Amazon Linux AMI release 2015.03

ClamAVインストール

$ sudo yum -y install clamav
$ sudo yum -y install clamav-update

パターンファイル更新

設定ファイルの編集しますー

$ sudo vim /etc/freshclam.conf
### Exampleをコメント化
# Comment or remove the line below.
Example
↓
# Comment or remove the line below.
# Example

### コメント外す
#UpdateLogFile /var/log/freshclam.log
↓
UpdateLogFile /var/log/freshclam.log

### コメントアウトを外す
#LogTime yes
↓
LogTime yes

パターンファイル自動更新

5分単位で自動更新されるように設定します。

$ sudo vim /etc/cron.d/clamav-update
### 時間間隔を変更
0  */3 * * * root /usr/share/clamav/freshclam-sleep
↓
0  */5 * * * root /usr/share/clamav/freshclam-sleep

自動更新の有効化

自動更新の有効化を実施します。

$ sudo vim /etc/sysconfig/freshclam
### コメント化
FRESHCLAM_DELAY=disabled-warn  # REMOVE ME#FRESHCLAM_DELAY=disabled-warn  # REMOVE ME

バージョン確認

$ sigtool --version
ClamAV 0.98.7/20394/Thu Apr 30 01:37:08 2015

パターンファイルのダウンロード先変更

パターンファイルのダウンロード先を日本とアメリカに設定します。
 ※ダウンロードが集中すると失敗する可能性があるため

### デフォルトをコメントアウト
#DatabaseMirror database.clamav.net

### 追加
DatabaseMirror db.jp.clamav.net
DatabaseMirror db.us.clamav.net

パターンファイルの更新

手動でパターンファイルの更新をします。

$ sudo freshclam

スキャンテスト

アンチウィルスのテストファイルとして利用されるeicarを作成します。
テキストファイルにテストコードを埋め込みます。

$ vim ~/eicar.com
X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*

準備できたので、スキャンしますー

$ sudo clamscan -r -i ~

----------- SCAN SUMMARY -----------
Known viruses: 6260545
Engine version: 0.98.7
Scanned directories: 1
Scanned files: 7
Infected files: 1
Data scanned: 0.02 MB
Data read: 0.01 MB (ratio 2.00:1)
Time: 11.612 sec (0 m 11 s)

スキャン結果に「Infected files: 1」と検出されましたね。
ということで、以上でClamAVのインストール方法でしたーヽ(*゚д゚)ノ

補足

ClamAVのバージョンが低いと以下のように怒られます。
最新版にアップデートするか、もしくは、2017.3のAmazon Linux AMIを使用することで、ClamAVのパッケージが最新化できます。
Amazon Linux AMI 2017.3 Packages

$ sudo freshclam
ClamAV update process started at Sun Apr 16 11:05:13 2017
WARNING: Your ClamAV installation is OUTDATED!
WARNING: Local version: 0.98.7 Recommended version: 0.99.2

続きを読む

ECSでGPUを扱うためのAMI作成 by Amazon Linux Deep Learning AMI

結論

ここ見れば一発だった
http://docs.aws.amazon.com/ja_jp/batch/latest/userguide/batch-gpu-ami.html

概要

scriptとかは変更があるかもしれないので転記しません。上記URLを参照してください。
以下の項番は上記URLの番号と合わせています。

  1. Amazon Linux Deep Learning AMIを起動する

    1. 強いて言うならp2で立ち上げた方が楽しい
    2. でも高いからSpotInstanceを使おう。マーケットプレイスの画面から進むとSpotInstanceが選択出来た
  2. SSHで接続する
  3. URL内のconfigure-gpu.shを作成する
  4. configure-gpu.shを実行する(結構待つ)
  5. Dockerコンテナを実行して、インストールされているドライバにアクセスできることを確認する(以下のような結果が出力されること)
  6. ゴミ掃除をする
No.5の実行結果
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 367.57                 Driver Version: 367.57                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla K80           On   | 0000:00:1E.0     Off |                    0 |
| N/A   47C    P8    26W / 149W |      0MiB / 11439MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+


+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

あとの作業

これをECSのAMIとして使って、ECSの特権フラグをOnにする

続きを読む

ド素人がAWSでRuby on Railsを導入したメモ

はじめに

いい加減見るだけでなくなにかしら自分用にでもいいからアウトプットしてみようと思ったので書いてみました。
ほぼグラフィックデザイナーとしてしかやってこなかった自分が軽い気持ちで手を出しているので、そもそも理解できてない部分が多い上に無駄な工程、逆になぜそこを書かないんだ的なところもどっさりあるかと思います。
(一応、自分のWindows10PCに仮想環境あり、PHPとかjQueryとかMysqlとかほんの触り程度に知っているくらいですが超初級レベルです。)

参考にした記事とやったこと

導入できました!

その後、rubyは入ってるのに
$ ruby -v
が効かなくてrehashも結局試したけどだめだったので一度接続しなおしたらバージョンが表示されました。導入できたようです。ヤッタネ!

今後の課題とか所感

Railsをインストールするディレクトリ
何も考えずec2-user直下にインストールしたがこれで果たして良かったのか・・・
まだ何もいじっていないのでわからんですがちゃんと調べてから導入したほうがいいなと後から感じました。

開発環境に慣れる
これから仕事で使うことになるので否が応でも慣れるしかない・・・まずは何ができて何ができないのかを理解するところからですかね。

まとめるのって難しい!
今回こうして書いてみたら思っていた以上に書き起こすのが難しかったのと、Markdown方式できれいな記事に仕上げるのもなかなか至難の技だということがわかりました。
あとはいろんな人の記事をもっと読んで、また自分が書こうと思ったときに書いてぼちぼち慣れていければなと思います。

続きを読む

Let’s Encrypt を使った SSL 設定 for Amazon Linux

SSLのサイトを作ってみたくなった

ちょっとした無償サービスを作るにあたって、Let’s Encrypt を使った SSL を試しに使ってみたくてやってみました。
環境は、Amazon Linux。

手順

$ wget https://dl.eff.org/certbot-auto
$ chmod a+x certbot-auto
$ ./certbot-auto
(中略)
FATAL: Amazon Linux support is very experimental at present...
if you would like to work on improving it, please ensure you have backups
and then run this script again with the --debug flag!
Alternatively, you can install OS dependencies yourself and run this script
again with --no-bootstrap.

Amazon Linux は、–debug をつけろというのでつけました。

$ ./certbot-auto --debug
(中略)
The following errors were reported by the server:

Domain: XXX.XXX.jp
Type:   connection
Detail: Failed to connect to XXX.XXX.XXX.XXX:443 for tls-sni-01 challenge
(後略)

よくよく調べると以下に該当。

https://letsencrypt.jp/usage/dvsni-challenge-error.html

セキュリティグループに、443を指定するのを忘れていたので指定して、コンソソールからインスタンス再起動。

$ ./certbot-auto renew

インストールが終わったら、httpd を再起動。

$ sudo service httpd graceful

https でアクセスして完了を確認。

参考

https://letsencrypt.jp/
http://qiita.com/takahiko/items/a08895550727b95b6c36
http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/SSL-on-an-instance.html#ssl_enable

続きを読む

AWS EBSのリサイズをシェルスクリプトにまとめてみた

はじめに

AWSのストレージサービスならばとりあえずS3を選んでおけば間違いはないのでしょうけど,既存サービスを短期間でAWSに移行する場合にはEBSを使うことがあるかと思います.以前はEBSの容量を変更できませんでしたので,事前に余裕を持って確保するか,都度容量を割り当ててデータを移行するか悩ましいところでした.

2017年2月にAWSよりEBSの新機能について発表があり,EBSの容量やタイプ,IOPSなどがオンザフライで変更できるようになりました.そこで,EBSの空き容量が閾値を下回ったときに拡張するシェルスクリプトを用意し,定期的に実行することでお財布への負担と管理運用作業を軽くしてみました.

https://aws.amazon.com/jp/blogs/news/amazon-ebs-update-new-elastic-volumes-change-everything/

書いてみた

  • スペシャルデバイス名とEBSボリューム名(Nameタグに割り当てた文字列)を指定して実行します.
  • 使用容量が95%に達したら,80%弱になるくらいに拡張します.
  • Amazon Linuxでroot権限で実行することを前提としています.
  • 2017年4月の時点でのAmazon Linuxにプレインストールされているaws-cliではaws ec2 modify-volumeに未対応なため,アップデートが必要でした.
  • JSONのパースにjqが必要なので,事前にインストールしてください.
#!/bin/sh
#
# $ sudo yum install jq
# $ sudo pip install -U awscli
# # sh ./ebs-resize.sh -d /dev/xvdf -v ebs-volume-name
#

usage() {
  echo "Usage: $0 -d device-name -v ebs-volume-name" 1>&2
  exit 1
}

while getopts d:v:h OPT
do
  case $OPT in
    'd')
      DEVICE_NAME=$OPTARG
      ;;
    'v')
      VOLUME_NAME=$OPTARG
      ;;
    'h')
      usage
      ;;
    ?)
      usage
      ;;
  esac
done

shift $((OPTIND - 1))

if test ${#DEVICE_NAME} -eq 0 -o ${#VOLUME_NAME} -eq 0; then
  usage
fi

df -k $DEVICE_NAME 1> /dev/null
if test "$?" -ne 0; then
  echo "$DEVICE_NAME is not found."
  exit 1
fi

export THRESHOLD_PERCENT=95
export EXPAND_RATE=1.25
export USED_PERCENT=`df -k $DEVICE_NAME | grep -v Filesystem | awk '{print $5}' | awk -F% '{print $1}'`
export CURRENT_SIZE=`df -k $DEVICE_NAME | grep -v Filesystem | awk '{print $2}'`
export NEW_SIZE=`echo "scale=0;$CURRENT_SIZE * $EXPAND_RATE / 1024 / 1024 + 1" | bc -l`
export AWS_DEFAULT_REGION=`curl --silent http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//g'`
export INSTANCE_ID=`curl --silent http://169.254.169.254/latest/meta-data/instance-id`
export VOLUME_ID=`aws ec2 describe-volumes --filter "Name=attachment.instance-id,Values=$INSTANCE_ID" "Name=tag:Name,Values=$VOLUME_NAME" |  jq -r '.Volumes[].VolumeId'`

if test ${#VOLUME_ID} -eq 0; then
  echo "$VOLUME_NAME is not found."
  exit 1
fi

if test $USED_PERCENT -ge $THRESHOLD_PERCENT; then
  aws ec2 modify-volume --volume-id $VOLUME_ID --size $NEW_SIZE
  resize2fs $DEVICE_NAME
fi

exit 0

おわりに

crontabに登録して1日1回程度動かすようにしましょう.なおaws ec2 modify-volumeは1度実行すると6時間は変更できないようです.ご利用は計画的に.

リンク

https://gist.github.com/stoshiya/4cafa50b34223aaa2a70c588abbede89

続きを読む