[Docker] コンテナ上のアプリを動かす

dockerの場合はdaemonで動かすのではなく、アプリを直接動かすのが基本
起動時のコマンドが全てのプロセスの原点となる
-> bashを抜けるとコンテナが停止する

$ sudo docker run -it –name centos centos:7.7.1908 bash

start.sh

#!bin/sh
handle() {
	echo 'handle sigterm/sigint'
	exit 0
}
trap handle TERM INT

nginx -g "daemon off;" &
wait

Dockerfile

From python:3.7.5-slim
RUN pip install flask=1.1.1
COPY ./server.py /server.py
ENV PORT 80
STOPSIGNAL SIGINT
CMD ["python", "-u", "/server.py"]

### supervisorで複数の子プロセス(アプリ本体)を管理

From centos:7.7.1908
RUN yum install -y epel-release \
	&& yum install -y http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm \
	&& yum -y install nginx openssh-server supervisor \
	&& rm -rf /var/cache/yum/* && yum clean all
RUN ssh-keygen -A
COPY supervisord.conf /etc/supervisord.conf
EXPOSE 22 80
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
[supervisord]
nodaemon=true

[program:sshd]
command=/usr/sbin/sshd -D
autostart=true
autorestart=true

[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true

うーん、結構奥が深いな…

[Docker] goのイメージ作成

main.go

package main

import(
	"net/http"
	"fmt"
)

func main(){
	http.HandleFunc("/",
		func(w http.ResponseWriter, r *http.Request){
			fmt.Fprintf(w, "hello go")
		})
	http.ListenAndServe(":80", nil)
}

Dockerfile

From golang:1.13.4-alpine3.10
WORKDIR /src
COPY ./main.go /src
RUN go build -o /usr/local/bin/startapp main.go
WORKDIR /
CMD ["/usr/local/bin/startapp"]

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

1. イメージ作成に必要な作業を別のコンテナで実施
2. 作業用コンテナで作成したイメージから本番ようイメージで使うデータを持ってくる

as builderとして1つ目の作業イメージに名前を与え、2つ目のイメージ後半で–from=builderとしてバイナリファイルをイメージ内部にコピー

From golang:1.13.4-alpine3.10 as builder
WORKDIR /src
COPY ./main.go /src
RUN go build -o start_appserver main.go

From alpine:3.10.3
COPY --from=builder /src/start_appserver /bin/start_appserver
CMD ["/bin/start_appserver"]

OSを搭載しないイメージ(Scratchと呼ぶ)
こうも書ける

From golang:1.13.4-alpine3.10 as builder
WORKDIR /src
COPY ./main.go /src
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a installsuffix cgo -o startapp main.go

From scratch
COPY --from=builder /src/startapp /startapp
CMD ["/startapp"]

自分が手動で展開できないものはDockerfile上の手順に落とし込むことはできない
– スクリプト構成を理解
– 公式を展開
– 機能を追加 
などを手を動かしてやる

差分イメージは減らす

RUN yum update \
	&& yum install -y \
		package-bar \
		package-baz \
		package-foo \
	&& rm -rf /var/cache/yum/* \
	&& yum clean all

AWS Direct ConnectのDC側のルータ設定

### 前提
AWS Direct Connectに接続するためには、BGPのTCP MD4認証機能に対応したファームウェアが必要

LAN1のインターフェイスの設定: ip lan1 address 192.168.100.1/24
LAN2のインターフェイスの設定: vlan lan2/1 802.1q vid=${VLAN番号}
※物理的な接続形態とは独立して、仮想的なLANセグメントを作る技術

なるほどー

[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, コンテナデータ・イメージ

うむー