[AWS] オートヒーリングとは

EC2でオートリカバリーとオートヒーリングがある
似てるが、Auto Healingは数を確保するのに対し、AutoRecoveryは自動復旧

### Auto Recovery
– Auto Recoveryは既存インスタンスのCloudWatchメトリクス監視をトリガーとするEC2インスタンスの自動復旧の仕組み
– 新しい仮想サーバホストへ変わる

### Auto Healing
Auto HealingはAutoScalingグループで設定したステータスチェック失敗時に、異常のあるEC2インスタンスを削除し、新しいインスタンスを起動して、常に一定数のEC2インスタンスを維持する構成
-> Auto Scalingで台数を設定

なるほどー
どっちの方が良いかわからんね。。

AWS Direct Connectの冗長化

### DirectConnectの冗長化
– ネットワーク機器や回線を含めたネットワーク経路を、災害や障害などで停止させることなく通信経路を確保し続けること
– 可用性を高め、障害が発生した際の停止時間を短縮する

### 冗長化の留意点
– コストが高い: 複数の専用線やネットワーク機器を用意しなければならないため
– 管理業務の増加: 冗長化構成により複雑化し、管理業務が増加する
– 万能ではない: リージョンの大規模障害などが起きた時は万能ではない

### マルチPOP接続
– クラウド環境への出入口となるネットワークの物理的な接続拠点を「クラウドPOP(Points of Presence)」と呼んでいます。専用線経由でPOP接続することでダイレクト接続が可能になる。
エクイティニックス、アット東京社

### 冗長化構成の例
– シングル構成
– シングルロケーションでの冗長構成
– デュアルロケーション
– 4接続確保

なるほどー
Direct Connectを使うとなると、ルータが高いみたいだけど、どうなんだろうか…

PCI DSSとは

PCI DSSとは?
– クレジットカード会員データを安全に取り扱う事を目的として策定されたクレジットカード業界のセキュリティ基準
– セキュリティ対策フレームワーク
– Payment Card Industry Data Security Standardの頭文字をとったもの

### 認証の取得
1. PCI国際協議会によって認定された審査機関(QSA=Qualified Security Assessor)による訪問審査を受けて、認証を得る

2. PCI国際協議会によって認定されたベンダー(ASV=Approved Scanning Vendor) のスキャンツールによって、四半期に1回以上の点検を受けて、サイトに脆弱性のないことの認証を得る

3. 自己問診
PCIDSSの要求事項に基づいた、アンケート形式によるチェック項目に回答して、すべて「Yes」であれば、準拠していると認められる

1つ適用というわけではなく、カード情報の取り扱い規模や事業形態によって複数を実施する
AISやSDPなど各カードブランドのプログラムによって適用するレベルが異なる

### PCI DSSで定められている目標と要件
– 安全なネットワークとシステムの構築と維持
1.カード会員データを保護するために、ファイアウォールをインストールして維持する
2.システムパスワードおよびその他のセキュリティパラメータにベンダ提供のデフォルト値を使用しない

– カード会員データの保護
3.保存されるカード会員データを保護する
4.オープンな公共ネットワーク経由でカード会員データを伝送する場合、暗号化する

– 脆弱性管理プログラムの整備
5.マルウェアにしてすべてのシステムを保護し、ウィルス対策ソフトウェアを定期的に更新する
6.安全性の高いシステムとアプリケーションを開発し、保守する

– 強力なアクセス制御手法の導入
7.カード会員データへのアクセスを、業務上必要な範囲内に制限する
8.システムコンポーネントへのアクセスを識別・認証する
9.カード会員データへの物理アクセスを制限する

– ネットワークの定期的な監視及びテスト
10.ネットワークリソースおよびカード会員データへのすべてのアクセスを追跡および監視する
11.セキュリティシステムおよびプロセスを定期的にテストする

– 情報セキュリティポリシーの整備
12.すべての担当者の情報セキュリティに対応するポリシーを整備する

なるほどー、結構厳しいな…

[Docker] コンテナでPostfixを立てたい

$ tree
.
├── Dockerfile
├── configs
│   ├── main.cf
│   └── sasl_passwd
├── docker-compose.yml
└── entrypoint.sh

docker-compose.yml

version: '3.8'
services:
  docker-ubuntu-postfix-example:
    build:
      context: ./
      dockerfile: dockerfile
    image: docker-ubuntu-postfix-example-image: lastes
    container_name: docker-ubuntu-postfix-example-container
    volumes:
      # Postfixの設定をマウント
      - type: bind
        source: ./configs/main.cf
        target: /etc/postfix/main.cf
      # SASL認証のパスワードをマウント
      - type: bind
        source: ./configs/sasl_passwd
        target: /etc/postfix/sasl_passwd

Dockerfile

FROM ubuntu:20.04

RUN apt update && apt upgrade -y

# postfix install
RUN DEBIAN_FRONTEND=noninteractive apt install postfix -y

# SMTPにはSMTP AUTHが必要
# SMTP AUTHの為のSASLにはCyrus SaslとCyrus IAMPを使う
RUN apt install sasl2-bin -y
RUN DEBIAN_FRONTEND=noninteractive apt install cyrus-imapd -y

# コンテナ起動のスクリプト
COPY ./entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]

entrypoint.sh

#!/bin/bash

# postfix起動
postfix start

# Postfixは/var/spool/postfixにchrootするので、
# /etc/resolv.confではなく/var/spool/postfix/etc/resolv.confを見に行く。

cp /etc/resolv.conf /var/spool/postfix/etc/resolv.conf

# SASL認証用テーブル作成
chown root:root /tec/postfix/sasl_passwd
postmap /etc/postfix/sasl_passwd

# postfixの設定を反映させる
postfix reload

# コンテナの起動を維持
tail -f /dev/null

entrypoint.sh

#!/bin/bash

# postfix起動
postfix start

# Postfixは/var/spool/postfixにchrootするので、
# /etc/resolv.confではなく/var/spool/postfix/etc/resolv.confを見に行く。

cp /etc/resolv.conf /var/spool/postfix/etc/resolv.conf

# SASL認証用テーブル作成
chown root:root /tec/postfix/sasl_passwd
postmap /etc/postfix/sasl_passwd

# postfixの設定を反映させる
postfix reload

# コンテナの起動を維持
tail -f /dev/null

main.cf

# ログの出力設定
mainlog_file = /var/log/mail.log

# SMTPリレーの設定
relayhost = 
smtp_sasl_auth_enable = 
smtp_sasl_mechanism_filter = 
smtp_sasl_security_options = 
smtp_sasl_password_maps = 

なるほどー、結構考えないといけないな…

ecs execの仕組み

AWS Systems Manager (SSM) セッションマネージャーを使用して実行中のコンテナとの接続を確立する
Linux コンテナでのみサポート

-> fargateでは特定のバージョン(1.4.0)以降を使うと、SSMをインストールする必要がない

CloudFormationのpropertiesで、EnableExecuteCommand: trueと書く

EcsExecRolePolicy:
  Type: AWS::IAM::Policy
  Properties:
    PolicyName: Ecs-exec-role
    PolicyDocument:
      Version: 2012-10-17
      Statement:
        - Effect: Allow
          Action:
            - "ssmmesages:CreateControlChannel"
            - "ssmmesages:CreateDataChannel"
            - "ssmmesages:OpenControlChannel"
            - "ssmmesages:OpenDataChannel"
          Resource: "*"
      Roles:

Service:
  Type: AWS::ECS::Service
  Properties:
    Cluster: !Ref Cluster
    DeploymentConfiguration:
      MaximumPercent: 200
      MinimumHealthyPercent: 100
    DesiredCount: !Ref DesiredCount
    EnableExecuteCommand: true
    LaunchType: FARGATE
    LoadBalancers:
      - ContainerName: app
        ContainerPort: 80
        TargetGroupArn: arn
    NetworkConfiguration:
      AwsvpcConfiguration:
        AssignPublicIp: ENABLED
        SecurityGroups:
          - arn
        Subnets:
          - arn
          - arn
    ServiceName: SampleFargate
    TaskDefinition: !RefTaskDefinition

なるほど、OKそうには見える

[Docker] Dockerfileと.dockerignore

Dockerfileはイメージを作成するための手順書(設計書)

### 開発フロー
1. 既存の開発環境を整える
2. 開発環境上でコードを書いて動作検証
3. 成果物ができたらリリース準備
4. 新規に本番環境をセットアップするか、既存の本番環境に変更を加える
5. 開発成果物を本番環境に移行し動作させる
6. 機能更新やアップデートが必要となり1に戻る

server.py

import os, flask
PORT = int(os.environ['PORT'])
app = flask.Flask('app server')
@app.route('/')
def index():
	return "hello Dockerfile"
app.run(debug=True, host='0.0.0.0', port=PORT)

Dockerfile

From python:3.7.5-slim
Label author="myname@example.com"
RUN pip install flask==1.1.1
COPY ./server.py /server.py
ENV PORT 80
CMD ["python", "-u", "/server.py"]

$ sudo docker image build ./ -t c4app1
$ sudo docker run –rm -d -p 8080:80 –name myapp c4app1

Dockerfileの内容がキャッシュされるので、頻繁に変更が発生する箇所はDockerfileの後半に持ってくる

### ディレクトリの
.dockerignoreを配置しておくと、DockerfileのCOPY命令などの対象から指定した形式のファイルは除外される

.dockerignore

**/__pycache__
**/.DS_Store
**/Thumbs.db

Dockerfile.local.yml

From centos:7.7.1908
RUN rpm -ivh http://nginx.org/package/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
RUN yum -y install nginx
VOLUME /volume
EXPOSE 80
USER nginx
COPY ./html/ /usr/share/nginx/html/
USER root
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]

expose: ポートの宣言
USER: ユーザの変更
ENTRYPOINT: イメージのデフォルト実行コマンドを定義

$ sudo docker image build -f Dockerfile.local.yml -t mynginx ./

なんやー ここにきて先が見えなくなってきた

[Docker] WordPress

$ sudo docker network create -d bridge wp-net
$ sudo docker run -d –network wp-net –name mysql \
–mount source=mysqlvolume,target=/var/lib/mysql \
–mount type=bind,source=/home/vagrant/dev/docker/book,target=/mysqlbackup \
-e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wordpress -e MYSQL_ROOT_PASSWORD=password mysql:5.7.28
$ sudo docker run -d –network wp-net -p 8080:80 \
-e WORDPRESS_DB_HOST=mysql:3306 -e WORDPRESS_DB_NAME=wordpress \
-e WORDPRESS_DB_USER=wordpress -e WORDPRESS_DB_PASSWORD=password \
–name wordpress wordpress:5.2.3-php7.3-apache

### Dockerエンジンの内部構造
Dockerd(デーモン)、containerd(コンテナとイメージ管理)、containerd-shim, runc, コンテナデータ・イメージ

うむー

[Docker] bind

$ sudo docker run -d –rm -p 8080:80 nginx:1.17.6-alpine
$ sudo docker container ls –format=’table {{.ID}}\t{{.Names}}\t{{.Ports}}’
$ sudo docker container port 09ee61149e2d
80/tcp -> 0.0.0.0:8080

Web系サービスを展開する場合、HTTPSの443とHTTP80が外部に公開される

コンテナ間の連携を行う場合は、bridgeではなく、作成したネットワークを利用する
作成したNATのネットワークが、内部のコンテナが他のコンテナを名前解決できる

### コンテナのログを設定
$ sudo docker container run –rm –name nginx -d nginx:1.17.6-alpine
$ sudo docker exec nginx cat /etc/nginx/nginx.conf
error_log /var/log/nginx/error.log warn;
access_log /var/log/nginx/access.log main;
エラー系のログが/var/log/nginx/error.logに書かれ、アクセスログが/var/log/nginx/access.logに書かれている

$ sudo docker exec nginx ls -l /var/log/nginx/error.log
lrwxrwxrwx 1 root root 11 Nov 20 2019 /var/log/nginx/error.log -> /dev/stderr
$ sudo docker exec nginx ls -l /var/log/nginx/access.log
lrwxrwxrwx 1 root root 11 Nov 20 2019 /var/log/nginx/access.log -> /dev/stdout

stderr, stdoutに出力されているのがわかります。

### bind
$ echo “hello bind” > hello1.txt
$ sudo docker run –rm -d –name bct \
–mount type=bind,source=/home/vagrant/dev/docker/book,target=/bindcont \
alpine:3.10.3 tail -f /dev/null
$ sudo docker exec bct ls /bindcont

$ sudo docker container exec bct touch /bindcont/hello2.txt
$ sudo docker stop bct
$ ls

readonlyにすることが多い

なるほど、標準出力、標準エラー出力はエイリアスが設定されてるんか…
標準出力は少し理解してきた

[Docker] 環境変数

nginxをリバースプロキシとして使用する
リバースプロキシーはロードバランサの一種で、クライアントからのアクセスを別のサーバに転送する

### 環境変数を使ったイメージのパラメーター
環境変数はシステムやアプリのパラメータを設定するもので、「キーとバリュー」の形式で管理されている。

アプリサーバー: 表示するメッセージ、ポート番号
リバースプロキシー: アプリサーバーのアドレス、待ち受けポート

pythonではosモジュールのenviron変数を使うことが一般的

server.py

import os, flask
MESSAGE = os.environ['MESSAGE']
PORT = int(os.environ['PORT'])

app = flask.Flask('c2env1_app')
@app.route('/')
def index():
	return MESSAGE

app.run(debug=True, host='0.0.0.0', port=PORT)

$ sudo docker run –name c2env1_app_base -d python:3.7.5-slim tail -f /dev/null
$ sudo docker exec c2env1_app_base pip install flask==1.1.1
$ sudo docker cp server.py c2env1_app_base:/
$ sudo docker stop c2env1_app_base
$ sudo docker commit c2env1_app_base c2env1_app
$ sudo docker run –name c2env1_app -p 8081:80 -d \
-e MESSAGE=”Hello Docker Env” -e PORT=80 \
c2env1_app python -u /server.py

nginx.tpl

events {
	worker_connections
}
http {
	server {
		server_name localhost:
		listen {{PORT}};
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr
		proxy_set_header X-Forwarded-Host $host
		proxy_set_header X-Forwarded-Server $host
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		location / {
			proxy_pass {{APP_SERVER}};
		}
	}
}

start.sh

#!/bin/sh
sed -e "s/{{PORT}}/$PORT/g" /etc/nginx/nginx.tpl > /etc/nginx/nginx.conf
sed -i -e "s^{{APP_SERVER}}^$APP_SERVER^g" /etc/nginx/nginx.conf
exec nginx -g "daemon off;"

$ sudo docker run –name c2env1_web_base -d nginx:1.17.6-alpine tail -f /dev/null
$ sudo docker cp start.sh c2env1_web_base:/
$ sudo docker exec c2env1_web_base chmod +x /start.sh
$ sudo docker cp nginx.tpl c2env1_web_base:/etc/nginx/
$ sudo docker stop c2env1_web_base
$ sudo docker commit c2env1_web_base c2env1_web

$ sudo docker run –name c2env1_web -p 8080:80 -d \
-e APP_SERVER=”http://172.17.0.2:80″ -e PORT=80 \
c2env1_web /start.sh

この様にも書ける
.env

APP_SERVER="http://172.17.0.2:80"
PORT=80

$ sudo docker run –name c2env1_web -p 8080:80 -d \
–env-file .env c2env1_web /start.sh

.envに変数入れて、–env-file .envでコマンド打てば、環境変数として扱えるのね。
これ凄いわ… ガチでビビるレベルや…

[Docker] flaskのアプリを作る

$ sudo docker container run –name base -it -p 8080:80 python:3.7.5-slim bash
# pip install flask==1.1.1

server.py

import flask
app = flask.Flask('app server')

@app.route('/')
def index():
	return 'Hello docker'

app.run(debug=True, host='0.0.0.0', port=80)

$ sudo docker container cp server.py base:/
# python server.py
Traceback (most recent call last):
File “server.py”, line 1, in
import os, flask
File “/usr/local/lib/python3.7/site-packages/flask/__init__.py”, line 14, in
from jinja2 import escape
ImportError: cannot import name ‘escape’ from ‘jinja2’ (/usr/local/lib/python3.7/site-packages/jinja2/__init__.py)

### コンテナからファイルを転送
$ sudo docker container cp base:/etc/hosts ./
$ cat hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 300da009fa4e

### コンテナのイメージ化
$ sudo docker commit base c2img1_app
$ sudo docker images;
REPOSITORY TAG IMAGE ID CREATED SIZE
c2img1_app latest 37a4ea8b1a13 5 seconds ago 189MB
$ sudo docker run –rm -p 8080:80 c2img1_app python -u /server.py
$ sudo docker image history c2img1_app

### imageをpush
$ sudo docker image tag c2img1_app ddddocker/c2img1_app:v1.0
$ sudo docker login
$ sudo docker push ddddocker/c2img1_app:v1.0

なんかやべえな…