├── .gitignore
├── README.md
├── circle.yml
└── fargate
├── Dockerfile
├── README.md
├── application
├── .gitignore
├── Dockerfile
├── Gopkg.lock
├── Gopkg.toml
├── deploy
│ ├── cfn-master.yaml
│ ├── cfn-release.yaml
│ ├── edge
│ │ └── buildspec.yml
│ ├── production
│ │ └── buildspec.yml
│ └── staging
│ │ └── buildspec.yml
├── diff
│ └── iam.yaml
└── main.go
├── infrastructure
├── .gitignore
├── diff
│ ├── orig.yaml
│ ├── production
│ └── staging
├── notification
│ └── index.js
└── sam.yaml
├── notebooks
├── 00-overview.ipynb
├── 01-provision-aws-resources.ipynb
├── 02-develop-with-git.ipynb
├── 03-deploy-to-staging.ipynb
├── 04-deploy-to-production.ipynb
├── 05-teardown-resources.ipynb
└── notebook-assets
│ ├── app-1.png
│ ├── infra-1.png
│ ├── infra-2.png
│ ├── whole-arch.png
│ ├── workflow-1.png
│ ├── workflow-2.png
│ └── workflow-3.png
└── notebooks_config
├── entrypoint.sh
└── jupyter_notebook.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | env.sh
3 | .ipynb_checkpoints
4 | packaged.yaml
5 | vendor
6 | docker-compose.yml
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ハンズオン
2 |
3 | [](https://circleci.com/gh/jawsug-container/hands-on)
4 |
5 | [](https://hub.docker.com/r/jawsug/container/)
6 |
7 | Supported tags and respective `Dockerfile` links:
8 |
9 | ・fargate-handson ([fargate/Dockerfile](https://github.com/jawsug-container/hands-on/blob/master/fargate/Dockerfile))
10 |
11 | ## 前提条件
12 |
13 | - 端末(Windows, Mac, ..)で Docker が利用できること
14 | - 利用可能な AWS アカウント、Administrator 権限のある IAM ユーザ、そのアクセスキーがあること
15 |
16 | ### Docker が利用できること
17 |
18 | Docker Store からインストーラーをダウンロードし、お手もとの環境へ Docker をインストールしてください。
19 | Windows へのインストールや動作確認がうまくできない場合は、EC2 の利用をご検討ください。
20 | (EC2 を利用する場合、パブリック IP アドレスの取得、8080 番ポートの解放が必要です)
21 |
22 | - Mac は [こちら](https://store.docker.com/editions/community/docker-ce-desktop-mac)
23 | - Windows は [こちら](https://store.docker.com/editions/community/docker-ce-desktop-windows)
24 | - EC2 は [こちら](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/docker-basics.html)
25 |
26 | 以下のコマンドで、Client と Server の情報が正常に返ってくることを確認してください。
27 |
28 | ```
29 | $ docker version
30 | ```
31 |
32 | 応答例)
33 |
34 | ```
35 | Client:
36 | Version: 18.03.1-ce
37 | API version: 1.37
38 | Go version: go1.9.5
39 | Git commit: 9ee9f40
40 | Built: Thu Apr 26 07:13:02 2018
41 | OS/Arch: darwin/amd64
42 | Experimental: false
43 | Orchestrator: swarm
44 |
45 | Server:
46 | Engine:
47 | Version: 18.03.1-ce
48 | API version: 1.37 (minimum version 1.12)
49 | Go version: go1.9.5
50 | Git commit: 9ee9f40
51 | Built: Thu Apr 26 07:22:38 2018
52 | OS/Arch: linux/amd64
53 | Experimental: true
54 | ```
55 |
56 | ### AWS の準備ができていること
57 |
58 | #### 1. AWS アカウントの開設
59 |
60 | 以下のサイトを参考に、AWS アカウントを用意してください。
61 | https://aws.amazon.com/jp/register-flow/
62 |
63 | #### 2. 重要!「AWS 利用開始時に最低限おさえておきたい 10 のこと」の確認
64 |
65 | 以下のスライドを読み、必要に応じて初期設定を変更してください。
66 | https://www.slideshare.net/AmazonWebServicesJapan/20180403-aws-white-belt-online-seminar-aws10
67 |
68 | #### 3. Administrator 権限のある IAM ユーザと、そのアクセスキーの発行
69 |
70 | IAM(Identity and Access Management)とは、AWS でのユーザーや権限を管理するサービスです。
71 | AWS をより安全に利用するために、初期設定されたルートユーザーとは別に、IAM ユーザーを用意します。
72 |
73 | 3.1. IAM 管理者ユーザーを作成します
74 |
75 | https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/getting-started_create-admin-group.html
76 |
77 | 3.2. アクセスキーを発行します
78 |
79 | 発行したアクセスキー・シークレットキーはどこか安全ば場所に保管しておいてください。
80 | インターネット上に流出させないよう、[git-secrets](https://github.com/awslabs/git-secrets) などをご検討ください。
81 | https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_access-keys.html
82 |
83 | #### 4. EC2 を起動・停止する
84 |
85 | AWS では開設直後のアカウントの場合、仮想サーバーの起動数などに制限がかかっていることがあります。
86 | 以下の手順に従い、 **t2.micro** でのインスタンス起動、設定、接続、および終了を一度実行してください。
87 |
88 | https://aws.amazon.com/jp/getting-started/tutorials/launch-a-virtual-machine/
89 |
90 |
91 | ## コンテンツ
92 |
93 | - [Fargate アプリケーションの継続的デリバリー](https://github.com/jawsug-container/hands-on/blob/master/fargate/README.md)
94 |
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | docker:
5 | - image: docker:18.06.0-ce-git
6 | steps:
7 | - checkout
8 | - setup_remote_docker
9 | - run:
10 | name: Install dependencies
11 | command: |
12 | apk add --no-cache py-pip
13 | pip install awscli
14 | - run:
15 | name: Run tests
16 | command: |
17 | docker run --rm -it -v $(pwd):/work -e IGNORE_PATH=/vendor/ supinf/shellcheck
18 |
--------------------------------------------------------------------------------
/fargate/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM docker:18.06.0-ce-dind
2 |
3 | ENV AWSCLI_VERSION=1.15.66 \
4 | JUPYTER_VERSION=1.0.0
5 |
6 | RUN apk --no-cache add python3 git
7 |
8 | # Install AWS CLI
9 | RUN apk --no-cache add groff less jq \
10 | && apk --no-cache add --virtual build-deps py3-pip \
11 | && pip3 install "awscli == ${AWSCLI_VERSION}" \
12 | && pip3 install yq \
13 | && find / -type d -name \__pycache__ -depth -exec rm -rf {} \; \
14 | && rm -rf /root/.cache \
15 | && apk del --purge -r build-deps
16 |
17 | # Install Jupyter notebook
18 | RUN apk --no-cache add bash tini \
19 | && apk --no-cache add --virtual build-deps build-base python3-dev \
20 | && pip3 install "jupyter == ${JUPYTER_VERSION}" \
21 | && pip3 install backcall bash_kernel \
22 | && python3 -m bash_kernel.install \
23 | && find / -type d -name tests -depth -exec rm -rf {} \; \
24 | && find / -type d -name \__pycache__ -depth -exec rm -rf {} \; \
25 | && rm -rf /root/.cache
26 |
27 | # Configure git to use CodeCommit as git repositories
28 | RUN git config --global credential.helper '!aws codecommit credential-helper $@' \
29 | && git config --global credential.UseHttpPath true
30 |
31 | WORKDIR /root/notebook
32 | ADD notebooks_config/jupyter_notebook.py /root/.jupyter/jupyter_notebook_config.py
33 | ADD notebooks /root/notebook
34 | ADD application /root/notebook/application
35 | ADD infrastructure /root/notebook/infrastructure
36 |
37 | ADD notebooks_config/entrypoint.sh /
38 | RUN chmod +x /entrypoint.sh
39 |
40 | VOLUME /root/config
41 |
42 | ENTRYPOINT ["/entrypoint.sh"]
43 | CMD ["tini", "--", "jupyter", "notebook"]
44 |
--------------------------------------------------------------------------------
/fargate/README.md:
--------------------------------------------------------------------------------
1 | # Fargate アプリケーションの継続的デリバリー
2 |
3 | この git リポジトリを clone する必要はありませんし、任意のディレクトリで動作します。
4 | Docker クライアントを操作できる端末を起動し、以下のステップを実行してください。
5 |
6 | ## ハンズオン環境の起動
7 |
8 | ### 1. アクセスキーをそれぞれ変数に設定します
9 |
10 | ```
11 | $ export AWS_ACCESS_KEY_ID=<あなたの AWS アクセスキー>
12 | $ export AWS_SECRET_ACCESS_KEY=<あなたの AWS シークレットキー>
13 | ```
14 |
15 | ### 2. git を扱うためのユーザー名とメールアドレス(任意)を変数に設定します
16 |
17 | このメールアドレスには、ハンズオンの中で、パイプライン実行のためのメールが送信されます。
18 |
19 | ```
20 | $ export GIT_USER_NAME=<あなたの git ユーザー名(任意)>
21 | $ export GIT_EMAIL_ADDRESS=<あなたの git ユーザーメールアドレス(有効なもの)>
22 | ```
23 |
24 | ### 3. ハンズオン環境の設定置き場を作ります
25 |
26 | ```
27 | $ docker volume create fargate-handson
28 | ```
29 |
30 | ### 4. ハンズオン環境を起動します
31 |
32 | ```
33 | $ docker run --rm -it -e AWS_DEFAULT_REGION=ap-northeast-1 \
34 | -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY \
35 | -e GIT_USER_NAME -e GIT_EMAIL_ADDRESS \
36 | -v /var/run/docker.sock:/var/run/docker.sock \
37 | -v fargate-handson:/root/config \
38 | -p 8080:8080 jawsug/container:fargate-handson
39 | ```
40 |
41 | ### 5. ブラウザで環境に接続します
42 |
43 | ブラウザで http://localhost:8080 を開いてください。
44 | (EC2 を利用している場合は、localhost を EC2 のパブリック IP アドレスに読み替えてください)
45 |
46 | パスワードを聞かれるので **jawsug** と入力してください。
47 |
48 | ### 6. ハンズオンの実施
49 |
50 | ハンズオンはブラウザ内の Jupyter notebook で行います。
51 | 以下の順序でハンズオンを進めてください。
52 |
53 | ```
54 | - 00-overview.ipynb
55 | - 01-provision-aws-resources.ipynb
56 | - 02-develop-with-git.ipynb
57 | - 03-deploy-to-staging.ipynb
58 | - 04-deploy-to-production.ipynb
59 | - 05-teardown-resources.ipynb
60 | ```
61 |
62 | ### 7. 後片付け
63 |
64 | `Ctrl + C` でコンテナに停止シグナルを送ると、Jupyter notebook から
65 | `Shutdown this notebook server (y/[n])?` と聞かれます。
66 | `y` と入力してコンテナを終了しましょう。
67 |
68 | 最後に設定を保存したボリュームを削除します。
69 |
70 | ```
71 | $ docker volume rm fargate-handson
72 | ```
73 |
74 | ## 参考
75 |
76 | - [AWS 公式: startup-kit-templates](https://github.com/aws-samples/startup-kit-templates/)
77 | - [AWS 公式: codepipeline-nested-cfn](https://github.com/aws-samples/codepipeline-nested-cfn/)
78 |
--------------------------------------------------------------------------------
/fargate/application/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 |
--------------------------------------------------------------------------------
/fargate/application/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM dockercloud/hello-world
2 |
3 | RUN sed -i -e "s/world/Fargate/g" /www/index.php
4 | RUN sed -i -e "s/hostname/project ID/g" /www/index.php
5 | RUN sed -i -e "s/HOSTNAME/PROJECT_ID/g" /www/index.php
6 |
--------------------------------------------------------------------------------
/fargate/application/Gopkg.lock:
--------------------------------------------------------------------------------
1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
2 |
3 |
4 | [[projects]]
5 | digest = "1:354011ee62a1d69d78dc7558813b10e8692e35087d1cc68ef0f18da54d3c6509"
6 | name = "github.com/aws/aws-sdk-go-v2"
7 | packages = [
8 | "aws",
9 | "aws/awserr",
10 | "aws/defaults",
11 | "aws/ec2metadata",
12 | "aws/ec2rolecreds",
13 | "aws/endpointcreds",
14 | "aws/endpoints",
15 | "aws/external",
16 | "aws/signer/v4",
17 | "aws/stscreds",
18 | "internal/awsutil",
19 | "internal/sdk",
20 | "private/protocol",
21 | "private/protocol/json/jsonutil",
22 | "private/protocol/jsonrpc",
23 | "private/protocol/query",
24 | "private/protocol/query/queryutil",
25 | "private/protocol/rest",
26 | "private/protocol/xml/xmlutil",
27 | "service/sts",
28 | "service/translate",
29 | ]
30 | pruneopts = "UT"
31 | revision = "ff1a530c31507c97cf5edbee226e604ca08661cc"
32 | version = "v2.0.0-preview.4"
33 |
34 | [[projects]]
35 | digest = "1:e361cb646a33874cf6521b5c4e77c9208b4b58c7fd3893b8c87f61f49b19d991"
36 | name = "github.com/caarlos0/env"
37 | packages = ["."]
38 | pruneopts = "UT"
39 | revision = "1cddc31c48c56ecd700d873edb9fd5b6f5df922a"
40 | version = "v3.3.0"
41 |
42 | [[projects]]
43 | digest = "1:fe8a03a8222d5b913f256972933d26d24ad7c8286692a42943bc01633cc8fce3"
44 | name = "github.com/go-ini/ini"
45 | packages = ["."]
46 | pruneopts = "UT"
47 | revision = "358ee7663966325963d4e8b2e1fbd570c5195153"
48 | version = "v1.38.1"
49 |
50 | [[projects]]
51 | digest = "1:e22af8c7518e1eab6f2eab2b7d7558927f816262586cd6ed9f349c97a6c285c4"
52 | name = "github.com/jmespath/go-jmespath"
53 | packages = ["."]
54 | pruneopts = "UT"
55 | revision = "0b12d6b5"
56 |
57 | [solve-meta]
58 | analyzer-name = "dep"
59 | analyzer-version = 1
60 | input-imports = [
61 | "github.com/aws/aws-sdk-go-v2/aws",
62 | "github.com/aws/aws-sdk-go-v2/aws/endpoints",
63 | "github.com/aws/aws-sdk-go-v2/aws/external",
64 | "github.com/aws/aws-sdk-go-v2/service/translate",
65 | "github.com/caarlos0/env",
66 | ]
67 | solver-name = "gps-cdcl"
68 | solver-version = 1
69 |
--------------------------------------------------------------------------------
/fargate/application/Gopkg.toml:
--------------------------------------------------------------------------------
1 | # Gopkg.toml example
2 | #
3 | # Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
4 | # for detailed Gopkg.toml documentation.
5 | #
6 | # required = ["github.com/user/thing/cmd/thing"]
7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
8 | #
9 | # [[constraint]]
10 | # name = "github.com/user/project"
11 | # version = "1.0.0"
12 | #
13 | # [[constraint]]
14 | # name = "github.com/user/project2"
15 | # branch = "dev"
16 | # source = "github.com/myfork/project2"
17 | #
18 | # [[override]]
19 | # name = "github.com/x/y"
20 | # version = "2.4.0"
21 | #
22 | # [prune]
23 | # non-go = false
24 | # go-tests = true
25 | # unused-packages = true
26 |
27 |
28 | [[constraint]]
29 | name = "github.com/aws/aws-sdk-go-v2"
30 | version = "2.0.0-preview.4"
31 |
32 | [[constraint]]
33 | name = "github.com/caarlos0/env"
34 | version = "3.3.0"
35 |
36 | [prune]
37 | go-tests = true
38 | unused-packages = true
39 |
--------------------------------------------------------------------------------
/fargate/application/deploy/cfn-master.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 | Description: "A fargate application"
3 |
4 | Outputs:
5 | Cluster:
6 | Description: the ECS cluster name
7 | Value: !Ref Cluster
8 |
9 | Metadata:
10 | AWS::CloudFormation::Interface:
11 | ParameterGroups:
12 | - Label:
13 | default: Basic Configurations
14 | Parameters:
15 | - ProjectID
16 | - Label:
17 | default: Application Configurations
18 | Parameters:
19 | - DockerImage
20 | - BasicAuthUsername
21 | - BasicAuthPassword
22 | - ContainerCpu
23 | - ContainerMemory
24 |
25 | Parameters:
26 | ProjectID:
27 | Type: String
28 |
29 | DockerImage:
30 | Type: String
31 |
32 | BasicAuthUsername:
33 | Type: String
34 | Default: ""
35 |
36 | BasicAuthPassword:
37 | Type: String
38 | Default: ""
39 | NoEcho: true
40 |
41 | ContainerCpu:
42 | Type: Number
43 | Description: Amount of CPU for the container
44 | Default: 256
45 | MinValue: 256
46 | MaxValue: 4096
47 | ConstraintDescription: "Value must be between 256 and 4096 - see: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#task_size"
48 |
49 | ContainerMemory:
50 | Type: Number
51 | Description: Amount of memory for the container
52 | Default: 512
53 | MinValue: 512
54 | MaxValue: 30720
55 | ConstraintDescription: "Value must be between 512 and 30720 - see: https://aws.amazon.com/fargate/pricing/"
56 |
57 | Resources:
58 |
59 | # Fargate のコントロールプレインとなる ECS クラスタ
60 | Cluster:
61 | Type: AWS::ECS::Cluster
62 | Properties:
63 | ClusterName: !Ref AWS::StackName
64 |
65 | # アプリケーションログの出力先
66 | CloudWatchLogsGroup:
67 | Type: AWS::Logs::LogGroup
68 | Properties:
69 | RetentionInDays: 1
70 |
71 | # Fargate の起動に必要な権限
72 | ExecutionRole:
73 | Type: AWS::IAM::Role
74 | Properties:
75 | AssumeRolePolicyDocument:
76 | Statement:
77 | - Effect: Allow
78 | Action: sts:AssumeRole
79 | Principal:
80 | Service: ecs-tasks.amazonaws.com
81 | ManagedPolicyArns:
82 | - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
83 | Path: /
84 |
85 | # Fargate(アプリケーション)に付与する権限
86 | TaskRole:
87 | Type: AWS::IAM::Role
88 | Properties:
89 | AssumeRolePolicyDocument:
90 | Statement:
91 | - Effect: Allow
92 | Action: sts:AssumeRole
93 | Principal:
94 | Service: ecs-tasks.amazonaws.com
95 | ManagedPolicyArns:
96 | - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
97 | Path: /
98 |
99 | # Fargate(アプリケーション)の定義
100 | FargateTaskDefinition:
101 | Type: AWS::ECS::TaskDefinition
102 | Properties:
103 | Family: !Ref AWS::StackName
104 | ExecutionRoleArn: !GetAtt ExecutionRole.Arn
105 | RequiresCompatibilities:
106 | - FARGATE
107 | ContainerDefinitions:
108 | - Name: app
109 | Image: !Ref DockerImage
110 | Essential: true
111 | PortMappings:
112 | - ContainerPort: 80
113 | Environment:
114 | - Name: PROJECT_ID
115 | Value: !Ref ProjectID
116 | - Name: BASIC_AUTH_USER
117 | Value: !Ref BasicAuthUsername
118 | - Name: BASIC_AUTH_PASS
119 | Value: !Ref BasicAuthPassword
120 | LogConfiguration:
121 | LogDriver: awslogs
122 | Options:
123 | awslogs-region: !Ref AWS::Region
124 | awslogs-group: !Ref CloudWatchLogsGroup
125 | awslogs-stream-prefix: fargate
126 | Cpu: !Ref ContainerCpu
127 | Memory: !Ref ContainerMemory
128 | NetworkMode: awsvpc
129 | TaskRoleArn: !GetAtt TaskRole.Arn
130 |
131 | # Fargate の外部インターフェイスの定義
132 | FargateService:
133 | Type: AWS::ECS::Service
134 | Properties:
135 | Cluster: !Ref Cluster
136 | LaunchType: FARGATE
137 | DesiredCount: 1
138 | TaskDefinition: !Ref FargateTaskDefinition
139 | NetworkConfiguration:
140 | AwsvpcConfiguration:
141 | AssignPublicIp: ENABLED
142 | SecurityGroups:
143 | - Fn::ImportValue: !Sub PublicAccess-${ProjectID}
144 | Subnets:
145 | - Fn::ImportValue: !Sub PublicSubnet1-${ProjectID}
146 | - Fn::ImportValue: !Sub PublicSubnet2-${ProjectID}
147 |
--------------------------------------------------------------------------------
/fargate/application/deploy/cfn-release.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 | Description: "A fargate application"
3 |
4 | Outputs:
5 | Cluster:
6 | Description: the ECS cluster name
7 | Value: !Ref Cluster
8 |
9 | LoadBalancerDNSName:
10 | Value: !GetAtt LoadBalancer.DNSName
11 |
12 | Metadata:
13 | AWS::CloudFormation::Interface:
14 | ParameterGroups:
15 | - Label:
16 | default: Basic Configurations
17 | Parameters:
18 | - ProjectID
19 | - Label:
20 | default: Application Configurations
21 | Parameters:
22 | - DockerImage
23 | - BasicAuthUsername
24 | - BasicAuthPassword
25 | - ContainerCpu
26 | - ContainerMemory
27 | - TaskMinContainerCount
28 | - TaskMaxContainerCount
29 |
30 | Parameters:
31 | ProjectID:
32 | Type: String
33 |
34 | DockerImage:
35 | Type: String
36 |
37 | BasicAuthUsername:
38 | Type: String
39 | Default: ""
40 |
41 | BasicAuthPassword:
42 | Type: String
43 | Default: ""
44 | NoEcho: true
45 |
46 | ContainerCpu:
47 | Type: Number
48 | Description: Amount of CPU for the container
49 | Default: 256
50 | MinValue: 256
51 | MaxValue: 4096
52 | ConstraintDescription: "Value must be between 256 and 4096 - see: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#task_size"
53 |
54 | ContainerMemory:
55 | Type: Number
56 | Description: Amount of memory for the container
57 | Default: 512
58 | MinValue: 512
59 | MaxValue: 30720
60 | ConstraintDescription: "Value must be between 512 and 30720 - see: https://aws.amazon.com/fargate/pricing/"
61 |
62 | # Auto scaling container counts
63 | TaskMinContainerCount:
64 | Type: Number
65 | Description: Minimum number of containers to run for the service
66 | Default: 1
67 | MinValue: 1
68 | ConstraintDescription: Value must be at least one
69 |
70 | TaskMaxContainerCount:
71 | Type: Number
72 | Description: Maximum number of containers to run for the service when auto scaling out
73 | Default: 2
74 | MinValue: 1
75 | ConstraintDescription: Value must be at least one
76 |
77 | # Scaling params
78 | DefaultServiceScaleEvaluationPeriods:
79 | Description: The number of periods over which data is compared to the specified threshold
80 | Type: Number
81 | Default: 2
82 | MinValue: 2
83 |
84 | DefaultServiceCpuScaleOutThreshold:
85 | Type: Number
86 | Description: Average CPU value to trigger auto scaling out
87 | Default: 50
88 | MinValue: 0
89 | MaxValue: 100
90 | ConstraintDescription: Value must be between 0 and 100
91 |
92 | DefaultServiceCpuScaleInThreshold:
93 | Type: Number
94 | Description: Average CPU value to trigger auto scaling in
95 | Default: 25
96 | MinValue: 0
97 | MaxValue: 100
98 | ConstraintDescription: Value must be between 0 and 100
99 |
100 | Resources:
101 |
102 | # Fargate のコントロールプレインとなる ECS クラスタ
103 | Cluster:
104 | Type: AWS::ECS::Cluster
105 | Properties:
106 | ClusterName: !Ref AWS::StackName
107 |
108 | # アプリケーションログの出力先
109 | CloudWatchLogsGroup:
110 | Type: AWS::Logs::LogGroup
111 | Properties:
112 | RetentionInDays: 1
113 |
114 | # Fargate の起動に必要な権限
115 | ExecutionRole:
116 | Type: AWS::IAM::Role
117 | Properties:
118 | AssumeRolePolicyDocument:
119 | Statement:
120 | - Effect: Allow
121 | Action: sts:AssumeRole
122 | Principal:
123 | Service: ecs-tasks.amazonaws.com
124 | ManagedPolicyArns:
125 | - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
126 | Path: /
127 |
128 | # Fargate(アプリケーション)に付与する権限
129 | TaskRole:
130 | Type: AWS::IAM::Role
131 | Properties:
132 | AssumeRolePolicyDocument:
133 | Statement:
134 | - Effect: Allow
135 | Action: sts:AssumeRole
136 | Principal:
137 | Service: ecs-tasks.amazonaws.com
138 | ManagedPolicyArns:
139 | - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
140 | Path: /
141 |
142 | # Fargate(アプリケーション)の定義
143 | FargateTaskDefinition:
144 | Type: AWS::ECS::TaskDefinition
145 | Properties:
146 | Family: !Ref AWS::StackName
147 | ExecutionRoleArn: !GetAtt ExecutionRole.Arn
148 | RequiresCompatibilities:
149 | - FARGATE
150 | ContainerDefinitions:
151 | - Name: app
152 | Image: !Ref DockerImage
153 | Essential: true
154 | PortMappings:
155 | - ContainerPort: 80
156 | Environment:
157 | - Name: PROJECT_ID
158 | Value: !Ref ProjectID
159 | - Name: BASIC_AUTH_USER
160 | Value: !Ref BasicAuthUsername
161 | - Name: BASIC_AUTH_PASS
162 | Value: !Ref BasicAuthPassword
163 | LogConfiguration:
164 | LogDriver: awslogs
165 | Options:
166 | awslogs-region: !Ref AWS::Region
167 | awslogs-group: !Ref CloudWatchLogsGroup
168 | awslogs-stream-prefix: fargate
169 | Cpu: !Ref ContainerCpu
170 | Memory: !Ref ContainerMemory
171 | NetworkMode: awsvpc
172 | TaskRoleArn: !GetAtt TaskRole.Arn
173 |
174 | # Fargate の外部インターフェイスの定義
175 | FargateService:
176 | Type: AWS::ECS::Service
177 | Properties:
178 | Cluster: !Ref Cluster
179 | LaunchType: FARGATE
180 | DesiredCount: !Ref TaskMinContainerCount
181 | TaskDefinition: !Ref FargateTaskDefinition
182 | LoadBalancers:
183 | - ContainerName: app
184 | ContainerPort: 80
185 | TargetGroupArn: !Ref TargetGroup
186 | NetworkConfiguration:
187 | AwsvpcConfiguration:
188 | AssignPublicIp: ENABLED
189 | SecurityGroups:
190 | - Fn::ImportValue: !Sub InternalAccess-${ProjectID}
191 | Subnets:
192 | - Fn::ImportValue: !Sub PublicSubnet1-${ProjectID}
193 | - Fn::ImportValue: !Sub PublicSubnet2-${ProjectID}
194 | DependsOn:
195 | - LoadBalancer
196 | - Listener
197 | - TargetGroup
198 | - ListenerRule
199 |
200 | # フロントエンドのロードバランサー
201 | LoadBalancer:
202 | Type: AWS::ElasticLoadBalancingV2::LoadBalancer
203 | Properties:
204 | Type: application
205 | Scheme: internet-facing
206 | IpAddressType: ipv4
207 | LoadBalancerAttributes:
208 | - Key: deletion_protection.enabled
209 | Value: false
210 | - Key: idle_timeout.timeout_seconds
211 | Value: 30
212 | Subnets:
213 | - Fn::ImportValue: !Sub PublicSubnet1-${ProjectID}
214 | - Fn::ImportValue: !Sub PublicSubnet2-${ProjectID}
215 | SecurityGroups:
216 | - Fn::ImportValue: !Sub PublicAccess-${ProjectID}
217 |
218 | Listener:
219 | Type: AWS::ElasticLoadBalancingV2::Listener
220 | Properties:
221 | DefaultActions:
222 | - Type: forward
223 | TargetGroupArn: !Ref TargetGroup
224 | LoadBalancerArn: !Ref LoadBalancer
225 | Protocol: HTTP
226 | Port: 80
227 |
228 | TargetGroup:
229 | Type: AWS::ElasticLoadBalancingV2::TargetGroup
230 | Properties:
231 | VpcId:
232 | Fn::ImportValue: !Sub VPC-${ProjectID}
233 | TargetType: ip
234 | Protocol: HTTP
235 | Port: 80
236 | HealthCheckProtocol: HTTP
237 | HealthCheckPath: /health
238 | Matcher:
239 | HttpCode: 200
240 | HealthCheckIntervalSeconds: 10
241 | HealthCheckTimeoutSeconds: 5
242 | HealthyThresholdCount: 2
243 | UnhealthyThresholdCount: 2
244 | TargetGroupAttributes:
245 | - Key: deregistration_delay.timeout_seconds
246 | Value: 30
247 | Tags:
248 | - Key: Stack
249 | Value: !Ref AWS::StackName
250 |
251 | ListenerRule:
252 | Type: AWS::ElasticLoadBalancingV2::ListenerRule
253 | Properties:
254 | Actions:
255 | - Type: forward
256 | TargetGroupArn: !Ref TargetGroup
257 | Conditions:
258 | - Field: path-pattern
259 | Values: [/]
260 | ListenerArn: !Ref Listener
261 | Priority: 1
262 |
263 | # オートスケーリングの設定
264 | AutoScalingRole:
265 | Type: AWS::IAM::Role
266 | Properties:
267 | AssumeRolePolicyDocument:
268 | Statement:
269 | - Effect: Allow
270 | Action: sts:AssumeRole
271 | Principal:
272 | Service: application-autoscaling.amazonaws.com
273 | Policies:
274 | - PolicyName: service-autoscaling
275 | PolicyDocument:
276 | Statement:
277 | - Effect: Allow
278 | Action:
279 | - application-autoscaling:*
280 | - cloudwatch:DescribeAlarms
281 | - cloudwatch:PutMetricAlarm
282 | - ecs:DescribeServices
283 | - ecs:UpdateService
284 | Resource: '*'
285 | Path: /
286 |
287 | ScalingTarget:
288 | Type: AWS::ApplicationAutoScaling::ScalableTarget
289 | Properties:
290 | ServiceNamespace: ecs
291 | ScalableDimension: ecs:service:DesiredCount
292 | ResourceId: !Sub service/${Cluster}/${FargateService.Name}
293 | RoleARN: !GetAtt AutoScalingRole.Arn
294 | MinCapacity: !Ref TaskMinContainerCount
295 | MaxCapacity: !Ref TaskMaxContainerCount
296 |
297 | ScaleOutPolicy:
298 | Type: AWS::ApplicationAutoScaling::ScalingPolicy
299 | Properties:
300 | PolicyName: ScaleOutPolicy
301 | PolicyType: StepScaling
302 | ScalingTargetId: !Ref ScalingTarget
303 | StepScalingPolicyConfiguration:
304 | AdjustmentType: ChangeInCapacity
305 | MetricAggregationType: Average
306 | StepAdjustments:
307 | - ScalingAdjustment: 1
308 | MetricIntervalLowerBound: 0
309 | Cooldown: 60
310 |
311 | ScaleInPolicy:
312 | Type: AWS::ApplicationAutoScaling::ScalingPolicy
313 | Properties:
314 | PolicyName: ScaleInPolicy
315 | PolicyType: StepScaling
316 | ScalingTargetId: !Ref ScalingTarget
317 | StepScalingPolicyConfiguration:
318 | AdjustmentType: ChangeInCapacity
319 | MetricAggregationType: Average
320 | StepAdjustments:
321 | - ScalingAdjustment: -1
322 | MetricIntervalUpperBound: 0
323 | Cooldown: 60
324 |
325 | ScaleOutAlarm:
326 | Type: AWS::CloudWatch::Alarm
327 | Properties:
328 | AlarmDescription: Alarm to add capacity if CPU is high
329 | Namespace: AWS/ECS
330 | MetricName: CPUUtilization
331 | Statistic: Average
332 | Dimensions:
333 | - Name: ClusterName
334 | Value: !Ref Cluster
335 | - Name: ServiceName
336 | Value: !GetAtt FargateService.Name
337 | ComparisonOperator: GreaterThanThreshold
338 | Period: 60
339 | EvaluationPeriods: !Ref DefaultServiceScaleEvaluationPeriods
340 | Threshold: !Ref DefaultServiceCpuScaleOutThreshold
341 | TreatMissingData: notBreaching
342 | AlarmActions:
343 | - !Ref ScaleOutPolicy
344 | DependsOn:
345 | - ScaleOutPolicy
346 |
347 | ScaleInAlarm:
348 | Type: AWS::CloudWatch::Alarm
349 | Properties:
350 | AlarmDescription: Alarm to reduce capacity if container CPU is low
351 | Namespace: AWS/ECS
352 | MetricName: CPUUtilization
353 | Statistic: Average
354 | Dimensions:
355 | - Name: ClusterName
356 | Value: !Ref Cluster
357 | - Name: ServiceName
358 | Value: !GetAtt FargateService.Name
359 | ComparisonOperator: LessThanThreshold
360 | Period: 300
361 | EvaluationPeriods: !Ref DefaultServiceScaleEvaluationPeriods
362 | Threshold: !Ref DefaultServiceCpuScaleInThreshold
363 | TreatMissingData: notBreaching
364 | AlarmActions:
365 | - !Ref ScaleInPolicy
366 | DependsOn:
367 | - ScaleInPolicy
368 |
--------------------------------------------------------------------------------
/fargate/application/deploy/edge/buildspec.yml:
--------------------------------------------------------------------------------
1 | version: 0.2
2 |
3 | phases:
4 | install:
5 | commands:
6 | - apt-get update
7 | - apt-get -y install python-pip
8 | - pip install --upgrade python
9 | - pip install --upgrade awscli
10 | pre_build:
11 | commands:
12 | - aws cloudformation validate-template --template-body fileb://deploy/cfn-master.yaml
13 | - IMAGE_NAME="${REPOSITORY_URI}:$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | head -c 7)"
14 | - BASIC_AUTH='"BasicAuthUsername":"","BasicAuthPassword":""'
15 | - |
16 | if [ -e "deploy/${ENVIRONMENT_NAME}/env.sh" ]; then
17 | $( cat "deploy/${ENVIRONMENT_NAME}/env.sh" )
18 | fi
19 | - $(aws ecr get-login --no-include-email)
20 | build:
21 | commands:
22 | - echo Build started on $(date)
23 | - docker build --tag ${IMAGE_NAME} .
24 | - docker push ${IMAGE_NAME}
25 | post_build:
26 | commands:
27 | - echo Build completed on $(date)
28 | - printf '{"Parameters":{"ProjectID":"%s","DockerImage":"%s",%s}}' ${PROJECT_ID} ${IMAGE_NAME} ${BASIC_AUTH} > config.json
29 |
30 | artifacts:
31 | files: config.json
32 |
--------------------------------------------------------------------------------
/fargate/application/deploy/production/buildspec.yml:
--------------------------------------------------------------------------------
1 | version: 0.2
2 |
3 | phases:
4 | pre_build:
5 | commands:
6 | - IMAGE_NAME="${REPOSITORY_URI}:$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | head -c 7)"
7 | build:
8 | commands:
9 | # アプリケーションのビルドは個別にせず、検証された staging と同じものを利用する
10 | - echo "do nothing."
11 | post_build:
12 | commands:
13 | # 本番環境は Basic 認証を行わない
14 | - printf '{"Parameters":{"ProjectID":"%s","DockerImage":"%s"}}' ${PROJECT_ID} ${IMAGE_NAME} > config.json
15 |
16 | artifacts:
17 | files: config.json
18 |
--------------------------------------------------------------------------------
/fargate/application/deploy/staging/buildspec.yml:
--------------------------------------------------------------------------------
1 | version: 0.2
2 |
3 | phases:
4 | install:
5 | commands:
6 | - apt-get update
7 | - apt-get -y install python-pip
8 | - pip install --upgrade python
9 | - pip install --upgrade awscli
10 | pre_build:
11 | commands:
12 | - aws cloudformation validate-template --template-body fileb://deploy/cfn-release.yaml
13 | - IMAGE_NAME="${REPOSITORY_URI}:$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | head -c 7)"
14 | - BASIC_AUTH='"BasicAuthUsername":"","BasicAuthPassword":""'
15 | - |
16 | if [ -e "deploy/${ENVIRONMENT_NAME}/env.sh" ]; then
17 | $( cat "deploy/${ENVIRONMENT_NAME}/env.sh" )
18 | fi
19 | - $(aws ecr get-login --no-include-email)
20 | build:
21 | commands:
22 | - echo Build started on $(date)
23 | - docker build --tag ${IMAGE_NAME} .
24 | - docker push ${IMAGE_NAME}
25 | post_build:
26 | commands:
27 | - echo Build completed on $(date)
28 | - printf '{"Parameters":{"ProjectID":"%s","DockerImage":"%s",%s}}' ${PROJECT_ID} ${IMAGE_NAME} ${BASIC_AUTH} > config.json
29 |
30 | artifacts:
31 | files: config.json
32 |
--------------------------------------------------------------------------------
/fargate/application/diff/iam.yaml:
--------------------------------------------------------------------------------
1 | --- cfn-master-old.yaml
2 | +++ cfn-master.yaml
3 | @@ -94,6 +94,7 @@
4 | Service: ecs-tasks.amazonaws.com
5 | ManagedPolicyArns:
6 | - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
7 | + - arn:aws:iam::aws:policy/TranslateReadOnly
8 | Path: /
9 |
10 | # Fargate(アプリケーション)の定義
11 |
--------------------------------------------------------------------------------
/fargate/application/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "html/template"
6 | "io"
7 | "log"
8 | "net/http"
9 | "strings"
10 | "time"
11 |
12 | "github.com/aws/aws-sdk-go-v2/aws"
13 | "github.com/aws/aws-sdk-go-v2/aws/endpoints"
14 | "github.com/aws/aws-sdk-go-v2/aws/external"
15 | "github.com/aws/aws-sdk-go-v2/service/translate"
16 | "github.com/caarlos0/env"
17 | )
18 |
19 | type config struct {
20 | BasicAuthUser string `env:"BASIC_AUTH_USER" envDefault:""`
21 | BasicAuthPass string `env:"BASIC_AUTH_PASS" envDefault:""`
22 | Port string `env:"PORT" envDefault:"80"`
23 | }
24 |
25 | var (
26 | cfg config
27 | svc *translate.Translate
28 | )
29 |
30 | func main() {
31 | cfg = config{}
32 | env.Parse(&cfg)
33 |
34 | awscfg, err := external.LoadDefaultAWSConfig()
35 | if err != nil {
36 | panic("Unable to load AWS SDK config, " + err.Error())
37 | }
38 | awscfg.Region = endpoints.UsEast2RegionID
39 | svc = translate.New(awscfg)
40 |
41 | http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
42 | w.WriteHeader(http.StatusOK)
43 | })
44 | http.Handle("/", wrap(cfg, logic))
45 |
46 | log.Printf("[service] listening on %s", cfg.Port)
47 | log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", cfg.Port), nil))
48 | }
49 |
50 | type custom struct {
51 | io.Writer
52 | http.ResponseWriter
53 | status int
54 | }
55 |
56 | func (r *custom) Write(b []byte) (int, error) {
57 | if r.Header().Get("Content-Type") == "" {
58 | r.Header().Set("Content-Type", http.DetectContentType(b))
59 | }
60 | return r.Writer.Write(b)
61 | }
62 |
63 | func (r *custom) WriteHeader(status int) {
64 | r.ResponseWriter.WriteHeader(status)
65 | r.status = status
66 | }
67 |
68 | func auth(c config, r *http.Request) bool {
69 | if username, password, ok := r.BasicAuth(); ok {
70 | return username == c.BasicAuthUser && password == c.BasicAuthPass
71 | }
72 | return false
73 | }
74 |
75 | func wrap(c config, f func(w http.ResponseWriter, r *http.Request)) http.Handler {
76 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
77 | if (len(c.BasicAuthUser) > 0) && (len(c.BasicAuthPass) > 0) && !auth(c, r) {
78 | w.Header().Set("WWW-Authenticate", `Basic realm="REALM"`)
79 | http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
80 | return
81 | }
82 | proc := time.Now()
83 | addr := r.RemoteAddr
84 | if candidate := r.Header["X-Forwarded-For"]; len(candidate) > 0 {
85 | addr = candidate[0]
86 | }
87 | ioWriter := w.(io.Writer)
88 | writer := &custom{Writer: ioWriter, ResponseWriter: w, status: http.StatusOK}
89 | f(writer, r)
90 |
91 | log.Printf("[%s] %.3f %d %s %s",
92 | addr, time.Now().Sub(proc).Seconds(),
93 | writer.status, r.Method, r.URL)
94 | })
95 | }
96 |
97 | func logic(w http.ResponseWriter, r *http.Request) {
98 | data := map[string]string{}
99 |
100 | if strings.EqualFold(r.Method, http.MethodPost) {
101 | from := r.FormValue("f")
102 |
103 | res, err := svc.TextRequest(&translate.TextInput{
104 | SourceLanguageCode: aws.String("ja"),
105 | TargetLanguageCode: aws.String("en"),
106 | Text: aws.String(from),
107 | }).Send()
108 | if err != nil {
109 | http.Error(w, err.Error(), http.StatusInternalServerError)
110 | return
111 | }
112 | data["from"] = from
113 | data["to"] = aws.StringValue(res.TranslatedText)
114 | }
115 | t := template.Must(template.New("html").Parse(`
116 |
117 |
118 |
119 | AWS SDK sample
120 |
121 |
125 |
126 |
127 |
132 |
133 | `))
134 | t.Execute(w, data)
135 | }
136 |
--------------------------------------------------------------------------------
/fargate/infrastructure/.gitignore:
--------------------------------------------------------------------------------
1 | cfn.yaml
2 |
--------------------------------------------------------------------------------
/fargate/infrastructure/diff/orig.yaml:
--------------------------------------------------------------------------------
1 | Transform: AWS::Serverless-2016-10-31
2 | AWSTemplateFormatVersion: '2010-09-09'
3 | Description: "A fargate application with a CI/CD pipeline"
4 |
5 | Outputs:
6 | GitHTTP:
7 | Description: CodeCommit clone URL for HTTPS
8 | Value: !GetAtt CodeRepository.CloneUrlHttp
9 |
10 | CodePipeline:
11 | Value: !Ref CodePipeline
12 |
13 | VPC:
14 | Value: !Ref VPC
15 | Export:
16 | Name: !Sub VPC-${ProjectID}
17 |
18 | PublicSubnet1:
19 | Value: !Ref PublicSubnet1
20 | Export:
21 | Name: !Sub PublicSubnet1-${ProjectID}
22 |
23 | PublicSubnet2:
24 | Value: !Ref PublicSubnet2
25 | Export:
26 | Name: !Sub PublicSubnet2-${ProjectID}
27 |
28 | PublicAccess:
29 | Value: !GetAtt PublicAccessSecurityGroup.GroupId
30 | Export:
31 | Name: !Sub PublicAccess-${ProjectID}
32 |
33 | InternalAccess:
34 | Value: !GetAtt InternalSecurityGroup.GroupId
35 | Export:
36 | Name: !Sub InternalAccess-${ProjectID}
37 |
38 | Metadata:
39 | AWS::CloudFormation::Interface:
40 | ParameterGroups:
41 | - Label:
42 | default: Basic Configurations
43 | Parameters:
44 | - ProjectID
45 | - EdgeStackName
46 | - Label:
47 | default: Pipeline Configurations
48 | Parameters:
49 | - S3BucketName
50 | - DockerBuildImage
51 | - ApprovalEmail
52 |
53 | Parameters:
54 | ProjectID:
55 | Type: String
56 |
57 | S3BucketName:
58 | Type: String
59 |
60 | EdgeStackName:
61 | Type: String
62 |
63 | DockerBuildImage:
64 | Type: String
65 | Default: "aws/codebuild/docker:17.09.0"
66 | Description: Docker Image used by CodeBuild
67 |
68 | ApprovalEmail:
69 | Type: String
70 | Description: Email address to which approval should be sent
71 | AllowedPattern: "([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)"
72 | ConstraintDescription: Must be a valid email address. (e.g. name@example.com)
73 |
74 | Globals:
75 | Function:
76 | Runtime: nodejs8.10
77 | MemorySize: 128
78 | Timeout: 30
79 |
80 | Resources:
81 |
82 | DockerRepository:
83 | Type: AWS::ECR::Repository
84 | Properties:
85 | RepositoryName: fargate-handson/api
86 | LifecyclePolicy:
87 | LifecyclePolicyText: |
88 | {
89 | "rules": [
90 | {
91 | "rulePriority": 1,
92 | "description": "Only keep untagged images for 1 day",
93 | "selection": {
94 | "tagStatus": "untagged",
95 | "countType": "sinceImagePushed",
96 | "countNumber": 1,
97 | "countUnit": "days"
98 | },
99 | "action": { "type": "expire" }
100 | }
101 | ]
102 | }
103 |
104 | CodeRepository:
105 | Type: AWS::CodeCommit::Repository
106 | Properties:
107 | RepositoryName: fargate-handson
108 | RepositoryDescription: Code repository for Fargate hands-on
109 |
110 | Topic:
111 | Type: AWS::SNS::Topic
112 | Properties:
113 | Subscription:
114 | - Protocol: email
115 | Endpoint: !Ref ApprovalEmail
116 |
117 | NotificationFuncRole:
118 | Type: AWS::IAM::Role
119 | Properties:
120 | AssumeRolePolicyDocument:
121 | Statement:
122 | - Effect: Allow
123 | Action: sts:AssumeRole
124 | Principal:
125 | Service: lambda.amazonaws.com
126 | Policies:
127 | - PolicyName: allow-codepipeline-and-sns
128 | PolicyDocument:
129 | Statement:
130 | - Effect: Allow
131 | Action:
132 | - codepipeline:*
133 | - sns:*
134 | Resource: "*"
135 | ManagedPolicyArns:
136 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
137 | Path: /
138 |
139 | NotificationFunc:
140 | Type: AWS::Serverless::Function
141 | Properties:
142 | FunctionName: fargate-cicd-notification
143 | CodeUri: notification/
144 | Handler: index.handler
145 | Environment:
146 | Variables:
147 | TOPIC_ARN: !Ref Topic
148 | Role: !GetAtt NotificationFuncRole.Arn
149 |
150 | CodeBuildServiceRole:
151 | Type: AWS::IAM::Role
152 | Properties:
153 | AssumeRolePolicyDocument:
154 | Statement:
155 | - Effect: Allow
156 | Action: sts:AssumeRole
157 | Principal:
158 | Service: codebuild.amazonaws.com
159 | Policies:
160 | - PolicyName: code-build-service
161 | PolicyDocument:
162 | Statement:
163 | - Effect: Allow
164 | Action:
165 | - cloudformation:ValidateTemplate
166 | Resource: "*"
167 | - Effect: Allow
168 | Action:
169 | - logs:CreateLogGroup
170 | - logs:CreateLogStream
171 | - logs:PutLogEvents
172 | - ecr:GetAuthorizationToken
173 | Resource: "*"
174 | - Effect: Allow
175 | Action:
176 | - s3:GetObject
177 | - s3:PutObject
178 | - s3:GetObjectVersion
179 | Resource: !Sub arn:aws:s3:::${S3BucketName}/*
180 | - Effect: Allow
181 | Action:
182 | - ecr:GetDownloadUrlForLayer
183 | - ecr:BatchGetImage
184 | - ecr:BatchCheckLayerAvailability
185 | - ecr:PutImage
186 | - ecr:InitiateLayerUpload
187 | - ecr:UploadLayerPart
188 | - ecr:CompleteLayerUpload
189 | Resource: !Sub arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/${DockerRepository}
190 | Path: /
191 |
192 | CodeBuild:
193 | Type: AWS::CodeBuild::Project
194 | Properties:
195 | Name: !Ref AWS::StackName
196 | ServiceRole: !Ref CodeBuildServiceRole
197 | Environment:
198 | ComputeType: BUILD_GENERAL1_SMALL
199 | Type: LINUX_CONTAINER
200 | Image: !Ref DockerBuildImage
201 | EnvironmentVariables:
202 | - Name: PROJECT_ID
203 | Value: !Ref ProjectID
204 | - Name: ENVIRONMENT_NAME
205 | Value: edge
206 | - Name: REPOSITORY_URI
207 | Value: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${DockerRepository}
208 | Artifacts:
209 | Type: CODEPIPELINE
210 | Source:
211 | Type: CODEPIPELINE
212 | BuildSpec: deploy/edge/buildspec.yml
213 |
214 | CodePipelineServiceRole:
215 | Type: AWS::IAM::Role
216 | Properties:
217 | AssumeRolePolicyDocument:
218 | Statement:
219 | - Effect: Allow
220 | Action: sts:AssumeRole
221 | Principal:
222 | Service: codepipeline.amazonaws.com
223 | Policies:
224 | - PolicyName: code-pipeline-service
225 | PolicyDocument:
226 | Statement:
227 | - Effect: Allow
228 | Action:
229 | - iam:PassRole
230 | - codecommit:ListRepositories
231 | - lambda:List*
232 | - cloudformation:CreateChangeSet
233 | - cloudformation:CreateStack
234 | - cloudformation:CreateUploadBucket
235 | - cloudformation:DeleteStack
236 | - cloudformation:Describe*
237 | - cloudformation:List*
238 | - cloudformation:UpdateStack
239 | - cloudformation:ValidateTemplate
240 | - cloudformation:ExecuteChangeSet
241 | Resource: "*"
242 | - Effect: Allow
243 | Action:
244 | - s3:PutObject
245 | - s3:GetObject
246 | - s3:GetObjectVersion
247 | Resource: !Sub arn:aws:s3:::${S3BucketName}/*
248 | - Effect: Allow
249 | Action:
250 | - codecommit:ListBranches
251 | - codecommit:BatchGetRepositories
252 | - codecommit:Get*
253 | - codecommit:GitPull
254 | - codecommit:UploadArchive
255 | - codecommit:CancelUploadArchive
256 | Resource:
257 | - !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${CodeRepository.Name}
258 | - Effect: Allow
259 | Action:
260 | - codebuild:StartBuild
261 | - codebuild:BatchGetBuilds
262 | Resource:
263 | - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${CodeBuild}
264 | - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:build/${CodeBuild}:*
265 | - Effect: Allow
266 | Action:
267 | - lambda:*
268 | Resource:
269 | - !GetAtt NotificationFunc.Arn
270 | Path: /
271 |
272 | CloudFormationRole:
273 | Type: AWS::IAM::Role
274 | Properties:
275 | AssumeRolePolicyDocument:
276 | Statement:
277 | - Effect: Allow
278 | Action: sts:AssumeRole
279 | Principal:
280 | Service: cloudformation.amazonaws.com
281 | Policies:
282 | - PolicyName: code-pipeline-service
283 | PolicyDocument:
284 | Statement:
285 | - Effect: Allow
286 | Action:
287 | - iam:*
288 | - ecs:RegisterTaskDefinition
289 | - ecs:DeregisterTaskDefinition
290 | # for stack update / deletion
291 | - ecs:CreateService
292 | - ecs:Delete*
293 | - logs:Delete*
294 | - cloudwatch:Delete*
295 | Resource: "*"
296 | ManagedPolicyArns:
297 | - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
298 | - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceAutoscaleRole
299 | - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole
300 | Path: /
301 |
302 | CodePipeline:
303 | Type: AWS::CodePipeline::Pipeline
304 | Properties:
305 | RoleArn: !GetAtt CodePipelineServiceRole.Arn
306 | ArtifactStore:
307 | Type: S3
308 | Location: !Ref S3BucketName
309 | Stages:
310 | - Name: Source
311 | Actions:
312 | - Name: Source
313 | ActionTypeId:
314 | Category: Source
315 | Provider: CodeCommit
316 | Owner: AWS
317 | Version: 1
318 | Configuration:
319 | RepositoryName: !GetAtt CodeRepository.Name
320 | BranchName: master
321 | OutputArtifacts:
322 | - Name: SourceCode
323 | RunOrder: 1
324 | - Name: Build
325 | Actions:
326 | - Name: Build
327 | ActionTypeId:
328 | Category: Build
329 | Provider: CodeBuild
330 | Owner: AWS
331 | Version: 1
332 | Configuration:
333 | ProjectName: !Ref CodeBuild
334 | InputArtifacts:
335 | - Name: SourceCode
336 | OutputArtifacts:
337 | - Name: Artifacts
338 | RunOrder: 1
339 | - Name: Deploy
340 | Actions:
341 | - Name: CreateEdgeChangeSet
342 | ActionTypeId:
343 | Category: Deploy
344 | Provider: CloudFormation
345 | Owner: AWS
346 | Version: 1
347 | Configuration:
348 | StackName: !Ref EdgeStackName
349 | ActionMode: CHANGE_SET_REPLACE
350 | ChangeSetName: ChangeSet
351 | RoleArn: !GetAtt CloudFormationRole.Arn
352 | Capabilities: CAPABILITY_NAMED_IAM
353 | TemplatePath: SourceCode::deploy/cfn-master.yaml
354 | TemplateConfiguration: Artifacts::config.json
355 | InputArtifacts:
356 | - Name: SourceCode
357 | - Name: Artifacts
358 | OutputArtifacts:
359 | - Name: CreatedEdgeChangeSet
360 | RunOrder: 1
361 | - Name: ExecuteEdgeChangeSet
362 | ActionTypeId:
363 | Category: Deploy
364 | Provider: CloudFormation
365 | Owner: AWS
366 | Version: 1
367 | Configuration:
368 | StackName: !Ref EdgeStackName
369 | ActionMode: CHANGE_SET_EXECUTE
370 | ChangeSetName: ChangeSet
371 | InputArtifacts:
372 | - Name: CreatedEdgeChangeSet
373 | OutputArtifacts:
374 | - Name: EdgeDeployed
375 | RunOrder: 2
376 | - Name: EdgeDeployedNotification
377 | ActionTypeId:
378 | Category: Invoke
379 | Provider: Lambda
380 | Owner: AWS
381 | Version: 1
382 | Configuration:
383 | FunctionName: !Ref NotificationFunc
384 | UserParameters: "{\"EnvName\":\"Edge\"}"
385 | InputArtifacts:
386 | - Name: EdgeDeployed
387 | OutputArtifacts:
388 | - Name: EdgeFinished
389 | RunOrder: 3
390 | DependsOn:
391 | - CodeBuild
392 | - CodePipelineServiceRole
393 |
394 | VPC:
395 | Type: AWS::EC2::VPC
396 | Properties:
397 | CidrBlock: 10.0.0.0/16
398 | EnableDnsSupport: true
399 | EnableDnsHostnames: true
400 | Tags:
401 | - Key: Name
402 | Value: Fargate Hands-on
403 |
404 | PublicSubnet1:
405 | Type: AWS::EC2::Subnet
406 | DependsOn: AttachGateway
407 | Properties:
408 | VpcId: !Ref VPC
409 | MapPublicIpOnLaunch: true
410 | AvailabilityZone: !Select [ 0, !GetAZs ]
411 | CidrBlock: 10.0.128.0/18
412 | Tags:
413 | - Key: Name
414 | Value: "Public Subnet 1"
415 |
416 | PublicSubnet2:
417 | Type: AWS::EC2::Subnet
418 | DependsOn: AttachGateway
419 | Properties:
420 | VpcId: !Ref VPC
421 | MapPublicIpOnLaunch: true
422 | AvailabilityZone: !Select [ 1, !GetAZs ]
423 | CidrBlock: 10.0.192.0/18
424 | Tags:
425 | - Key: Name
426 | Value: "Public Subnet 2"
427 |
428 | InternetGateway:
429 | Type: AWS::EC2::InternetGateway
430 | DependsOn: VPC
431 |
432 | AttachGateway:
433 | Type: AWS::EC2::VPCGatewayAttachment
434 | Properties:
435 | VpcId: !Ref VPC
436 | InternetGatewayId: !Ref InternetGateway
437 |
438 | PublicRouteTable:
439 | Type: AWS::EC2::RouteTable
440 | DependsOn: AttachGateway
441 | Properties:
442 | VpcId: !Ref VPC
443 | Tags:
444 | - Key: Name
445 | Value: Public
446 |
447 | PublicRoute:
448 | Type: AWS::EC2::Route
449 | DependsOn: AttachGateway
450 | Properties:
451 | RouteTableId: !Ref PublicRouteTable
452 | GatewayId: !Ref InternetGateway
453 | DestinationCidrBlock: 0.0.0.0/0
454 |
455 | PublicSubnet1RouteTableAssociation:
456 | Type: AWS::EC2::SubnetRouteTableAssociation
457 | DependsOn: AttachGateway
458 | Properties:
459 | SubnetId: !Ref PublicSubnet1
460 | RouteTableId: !Ref PublicRouteTable
461 |
462 | PublicSubnet2RouteTableAssociation:
463 | Type: AWS::EC2::SubnetRouteTableAssociation
464 | DependsOn: AttachGateway
465 | Properties:
466 | SubnetId: !Ref PublicSubnet2
467 | RouteTableId: !Ref PublicRouteTable
468 |
469 | PublicAccessSecurityGroup:
470 | Type: AWS::EC2::SecurityGroup
471 | Properties:
472 | GroupDescription: SecurityGroup for load balancers
473 | VpcId: !Ref VPC
474 | SecurityGroupIngress:
475 | - IpProtocol: tcp
476 | FromPort: 80
477 | ToPort: 80
478 | CidrIp: 0.0.0.0/0
479 | Tags:
480 | - Key: Name
481 | Value: PublicAccess
482 |
483 | InternalSecurityGroup:
484 | Type: AWS::EC2::SecurityGroup
485 | Properties:
486 | GroupDescription: SecurityGroup for internal access
487 | VpcId: !Ref VPC
488 | SecurityGroupIngress:
489 | - CidrIp: 10.0.0.0/16
490 | IpProtocol: -1
491 | Tags:
492 | - Key: Name
493 | Value: InternalAccess
494 |
495 | InternalSecurityGroupIngress:
496 | Type: AWS::EC2::SecurityGroupIngress
497 | Properties:
498 | GroupId: !Ref InternalSecurityGroup
499 | IpProtocol: -1
500 | SourceSecurityGroupId: !Ref InternalSecurityGroup
501 |
--------------------------------------------------------------------------------
/fargate/infrastructure/diff/production:
--------------------------------------------------------------------------------
1 | --- sam-staging.yaml
2 | +++ sam.yaml
3 | @@ -47,6 +47,7 @@
4 | - ProjectID
5 | - EdgeStackName
6 | - StagingStackName
7 | + - ProductionStackName
8 | - Label:
9 | default: Pipeline Configurations
10 | Parameters:
11 | @@ -67,6 +68,9 @@
12 | StagingStackName:
13 | Type: String
14 |
15 | + ProductionStackName:
16 | + Type: String
17 | +
18 | DockerBuildImage:
19 | Type: String
20 | Default: "aws/codebuild/docker:17.09.0"
21 | @@ -248,6 +252,29 @@
22 | Type: CODEPIPELINE
23 | BuildSpec: deploy/staging/buildspec.yml
24 |
25 | + # アプリケーションのテストやビルドの定義(本番環境)
26 | + CodeBuildProduction:
27 | + Type: AWS::CodeBuild::Project
28 | + Properties:
29 | + Name: !Sub ${AWS::StackName}-production
30 | + ServiceRole: !Ref CodeBuildServiceRole
31 | + Environment:
32 | + ComputeType: BUILD_GENERAL1_SMALL
33 | + Type: LINUX_CONTAINER
34 | + Image: !Ref DockerBuildImage
35 | + EnvironmentVariables:
36 | + - Name: PROJECT_ID
37 | + Value: !Ref ProjectID
38 | + - Name: ENVIRONMENT_NAME
39 | + Value: production
40 | + - Name: REPOSITORY_URI
41 | + Value: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${DockerRepository}
42 | + Artifacts:
43 | + Type: CODEPIPELINE
44 | + Source:
45 | + Type: CODEPIPELINE
46 | + BuildSpec: deploy/production/buildspec.yml
47 | +
48 | # 継続的インテグレーション/継続的デプロイのパイプラインに必要な権限
49 | CodePipelineServiceRole:
50 | Type: AWS::IAM::Role
51 | @@ -303,6 +330,8 @@
52 | - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:build/${CodeBuild}:*
53 | - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${CodeBuildStaging}
54 | - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:build/${CodeBuildStaging}:*
55 | + - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${CodeBuildProduction}
56 | + - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:build/${CodeBuildProduction}:*
57 | - Effect: Allow
58 | Action:
59 | - lambda:*
60 | @@ -475,6 +504,19 @@
61 | OutputArtifacts:
62 | - Name: Artifacts
63 | RunOrder: 1
64 | + - Name: ProdConfig
65 | + ActionTypeId:
66 | + Category: Build
67 | + Provider: CodeBuild
68 | + Owner: AWS
69 | + Version: 1
70 | + Configuration:
71 | + ProjectName: !Ref CodeBuildProduction
72 | + InputArtifacts:
73 | + - Name: SourceCode
74 | + OutputArtifacts:
75 | + - Name: ProdConfig
76 | + RunOrder: 1
77 | - Name: DeployToStaging
78 | Actions:
79 | - Name: CreateStagingChangeSet
80 | @@ -526,8 +568,70 @@
81 | OutputArtifacts:
82 | - Name: StagingFinished
83 | RunOrder: 3
84 | + - Name: DeployToProduction
85 | + Actions:
86 | + - Name: CreateProductionChangeSet
87 | + ActionTypeId:
88 | + Category: Deploy
89 | + Provider: CloudFormation
90 | + Owner: AWS
91 | + Version: 1
92 | + Configuration:
93 | + StackName: !Ref ProductionStackName
94 | + ActionMode: CHANGE_SET_REPLACE
95 | + ChangeSetName: ChangeSet
96 | + RoleArn: !GetAtt CloudFormationRole.Arn
97 | + Capabilities: CAPABILITY_NAMED_IAM
98 | + TemplatePath: SourceCode::deploy/cfn-release.yaml
99 | + TemplateConfiguration: ProdConfig::config.json
100 | + InputArtifacts:
101 | + - Name: SourceCode
102 | + - Name: ProdConfig
103 | + OutputArtifacts:
104 | + - Name: CreatedProductionChangeSet
105 | + RunOrder: 1
106 | + - Name: ProdApproval
107 | + ActionTypeId:
108 | + Category: Approval
109 | + Provider: Manual
110 | + Owner: AWS
111 | + Version: 1
112 | + Configuration:
113 | + NotificationArn: !Ref Topic
114 | + CustomData: Approve deployment in production.
115 | + RunOrder: 2
116 | + - Name: ExecuteProductionChangeSet
117 | + ActionTypeId:
118 | + Category: Deploy
119 | + Provider: CloudFormation
120 | + Owner: AWS
121 | + Version: 1
122 | + Configuration:
123 | + StackName: !Ref ProductionStackName
124 | + ActionMode: CHANGE_SET_EXECUTE
125 | + ChangeSetName: ChangeSet
126 | + InputArtifacts:
127 | + - Name: CreatedProductionChangeSet
128 | + OutputArtifacts:
129 | + - Name: ProductionDeployed
130 | + RunOrder: 3
131 | + - Name: ProductionDeployedNotification
132 | + ActionTypeId:
133 | + Category: Invoke
134 | + Provider: Lambda
135 | + Owner: AWS
136 | + Version: 1
137 | + Configuration:
138 | + FunctionName: !Ref NotificationFunc
139 | + UserParameters: "{\"EnvName\":\"Production\"}"
140 | + InputArtifacts:
141 | + - Name: ProductionDeployed
142 | + OutputArtifacts:
143 | + - Name: ProductionFinished
144 | + RunOrder: 4
145 | DependsOn:
146 | - CodeBuildStaging
147 | + - CodeBuildProduction
148 | - CodePipelineServiceRole
149 |
150 | # アプリケーションのための VPC
151 |
--------------------------------------------------------------------------------
/fargate/infrastructure/diff/staging:
--------------------------------------------------------------------------------
1 | --- sam-edge.yaml
2 | +++ sam.yaml
3 | @@ -10,6 +10,9 @@
4 | CodePipeline:
5 | Value: !Ref CodePipeline
6 |
7 | + CodePipelineRelease:
8 | + Value: !Ref CodePipelineRelease
9 | +
10 | VPC:
11 | Value: !Ref VPC
12 | Export:
13 | @@ -43,6 +46,7 @@
14 | Parameters:
15 | - ProjectID
16 | - EdgeStackName
17 | + - StagingStackName
18 | - Label:
19 | default: Pipeline Configurations
20 | Parameters:
21 | @@ -60,6 +64,9 @@
22 | EdgeStackName:
23 | Type: String
24 |
25 | + StagingStackName:
26 | + Type: String
27 | +
28 | DockerBuildImage:
29 | Type: String
30 | Default: "aws/codebuild/docker:17.09.0"
31 | @@ -218,6 +225,29 @@
32 | Type: CODEPIPELINE
33 | BuildSpec: deploy/edge/buildspec.yml
34 |
35 | + # アプリケーションのテストやビルドの定義(ステージング環境)
36 | + CodeBuildStaging:
37 | + Type: AWS::CodeBuild::Project
38 | + Properties:
39 | + Name: !Sub ${AWS::StackName}-staging
40 | + ServiceRole: !Ref CodeBuildServiceRole
41 | + Environment:
42 | + ComputeType: BUILD_GENERAL1_SMALL
43 | + Type: LINUX_CONTAINER
44 | + Image: !Ref DockerBuildImage
45 | + EnvironmentVariables:
46 | + - Name: PROJECT_ID
47 | + Value: !Ref ProjectID
48 | + - Name: ENVIRONMENT_NAME
49 | + Value: staging
50 | + - Name: REPOSITORY_URI
51 | + Value: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${DockerRepository}
52 | + Artifacts:
53 | + Type: CODEPIPELINE
54 | + Source:
55 | + Type: CODEPIPELINE
56 | + BuildSpec: deploy/staging/buildspec.yml
57 | +
58 | # 継続的インテグレーション/継続的デプロイのパイプラインに必要な権限
59 | CodePipelineServiceRole:
60 | Type: AWS::IAM::Role
61 | @@ -271,6 +301,8 @@
62 | Resource:
63 | - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${CodeBuild}
64 | - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:build/${CodeBuild}:*
65 | + - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${CodeBuildStaging}
66 | + - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:build/${CodeBuildStaging}:*
67 | - Effect: Allow
68 | Action:
69 | - lambda:*
70 | @@ -298,6 +330,9 @@
71 | - ecs:RegisterTaskDefinition
72 | - ecs:DeregisterTaskDefinition
73 | # for stack update / deletion
74 | + - elasticloadbalancing:ModifyTargetGroup
75 | + - elasticloadbalancing:Delete*
76 | + - application-autoscaling:*
77 | - ecs:CreateService
78 | - ecs:Delete*
79 | - logs:Delete*
80 | @@ -400,6 +435,99 @@
81 | RunOrder: 3
82 | DependsOn:
83 | - CodeBuild
84 | + - CodePipelineServiceRole
85 | +
86 | + # 継続的インテグレーション/継続的デプロイのパイプライン(ステージング・本番環境)
87 | + CodePipelineRelease:
88 | + Type: AWS::CodePipeline::Pipeline
89 | + Properties:
90 | + RoleArn: !GetAtt CodePipelineServiceRole.Arn
91 | + ArtifactStore:
92 | + Type: S3
93 | + Location: !Ref S3BucketName
94 | + Stages:
95 | + - Name: Source
96 | + Actions:
97 | + - Name: Source
98 | + ActionTypeId:
99 | + Category: Source
100 | + Provider: CodeCommit
101 | + Owner: AWS
102 | + Version: 1
103 | + Configuration:
104 | + RepositoryName: !GetAtt CodeRepository.Name
105 | + BranchName: release
106 | + OutputArtifacts:
107 | + - Name: SourceCode
108 | + RunOrder: 1
109 | + - Name: Build
110 | + Actions:
111 | + - Name: Build
112 | + ActionTypeId:
113 | + Category: Build
114 | + Provider: CodeBuild
115 | + Owner: AWS
116 | + Version: 1
117 | + Configuration:
118 | + ProjectName: !Ref CodeBuildStaging
119 | + InputArtifacts:
120 | + - Name: SourceCode
121 | + OutputArtifacts:
122 | + - Name: Artifacts
123 | + RunOrder: 1
124 | + - Name: DeployToStaging
125 | + Actions:
126 | + - Name: CreateStagingChangeSet
127 | + ActionTypeId:
128 | + Category: Deploy
129 | + Provider: CloudFormation
130 | + Owner: AWS
131 | + Version: 1
132 | + Configuration:
133 | + StackName: !Ref StagingStackName
134 | + ActionMode: CHANGE_SET_REPLACE
135 | + ChangeSetName: ChangeSet
136 | + RoleArn: !GetAtt CloudFormationRole.Arn
137 | + Capabilities: CAPABILITY_NAMED_IAM
138 | + TemplatePath: SourceCode::deploy/cfn-release.yaml
139 | + TemplateConfiguration: Artifacts::config.json
140 | + InputArtifacts:
141 | + - Name: SourceCode
142 | + - Name: Artifacts
143 | + OutputArtifacts:
144 | + - Name: CreatedStagingChangeSet
145 | + RunOrder: 1
146 | + - Name: ExecuteStagingChangeSet
147 | + ActionTypeId:
148 | + Category: Deploy
149 | + Provider: CloudFormation
150 | + Owner: AWS
151 | + Version: 1
152 | + Configuration:
153 | + StackName: !Ref StagingStackName
154 | + ActionMode: CHANGE_SET_EXECUTE
155 | + ChangeSetName: ChangeSet
156 | + InputArtifacts:
157 | + - Name: CreatedStagingChangeSet
158 | + OutputArtifacts:
159 | + - Name: StagingDeployed
160 | + RunOrder: 2
161 | + - Name: StagingDeployedNotification
162 | + ActionTypeId:
163 | + Category: Invoke
164 | + Provider: Lambda
165 | + Owner: AWS
166 | + Version: 1
167 | + Configuration:
168 | + FunctionName: !Ref NotificationFunc
169 | + UserParameters: "{\"EnvName\":\"Staging\"}"
170 | + InputArtifacts:
171 | + - Name: StagingDeployed
172 | + OutputArtifacts:
173 | + - Name: StagingFinished
174 | + RunOrder: 3
175 | + DependsOn:
176 | + - CodeBuildStaging
177 | - CodePipelineServiceRole
178 |
179 | # アプリケーションのための VPC
180 |
--------------------------------------------------------------------------------
/fargate/infrastructure/notification/index.js:
--------------------------------------------------------------------------------
1 | var AWS = require('aws-sdk');
2 |
3 | exports.handler = function(event, context) {
4 | var eventText = JSON.stringify(event, null, 2);
5 | console.log("Received event:", eventText);
6 |
7 | var job = event["CodePipeline.job"],
8 | jobId = job.id,
9 | params = JSON.parse(job.data.actionConfiguration.configuration.UserParameters);
10 |
11 | // Validate parameters passed in UserParameters
12 | if(! params || params.EnvName == '') {
13 | failure('The UserParameters is invalid');
14 | return;
15 | }
16 |
17 | // Publish to a SNS topic
18 | var sns = new AWS.SNS();
19 | sns.publish({
20 | TopicArn: process.env.TOPIC_ARN,
21 | Subject: "A new version was deployed via AWS CodePipeline",
22 | Message: "Successfully deployed a new version to "+params.EnvName+" fargate!"
23 | }, function (err, data) {
24 | if (err) {
25 | failure(err);
26 | return;
27 | }
28 | success("Function Finished.");
29 | });
30 |
31 | function success(message) {
32 | var api = new AWS.CodePipeline();
33 | api.putJobSuccessResult({jobId: jobId}, function (err, data) {
34 | if (err) {
35 | context.fail(err);
36 | } else {
37 | context.succeed(message);
38 | }
39 | });
40 | }
41 | function failure(message) {
42 | var api = new AWS.CodePipeline(),
43 | params = {
44 | jobId: jobId,
45 | failureDetails: {
46 | type: 'JobFailed',
47 | message: JSON.stringify(message),
48 | externalExecutionId: context.invokeid
49 | }
50 | };
51 | api.putJobFailureResult(params, function (err, data) {
52 | context.fail(message);
53 | });
54 | }
55 | };
56 |
--------------------------------------------------------------------------------
/fargate/infrastructure/sam.yaml:
--------------------------------------------------------------------------------
1 | Transform: AWS::Serverless-2016-10-31
2 | AWSTemplateFormatVersion: '2010-09-09'
3 | Description: "A fargate application with a CI/CD pipeline"
4 |
5 | Outputs:
6 | GitHTTP:
7 | Description: CodeCommit clone URL for HTTPS
8 | Value: !GetAtt CodeRepository.CloneUrlHttp
9 |
10 | CodePipeline:
11 | Value: !Ref CodePipeline
12 |
13 | VPC:
14 | Value: !Ref VPC
15 | Export:
16 | Name: !Sub VPC-${ProjectID}
17 |
18 | PublicSubnet1:
19 | Value: !Ref PublicSubnet1
20 | Export:
21 | Name: !Sub PublicSubnet1-${ProjectID}
22 |
23 | PublicSubnet2:
24 | Value: !Ref PublicSubnet2
25 | Export:
26 | Name: !Sub PublicSubnet2-${ProjectID}
27 |
28 | PublicAccess:
29 | Value: !GetAtt PublicAccessSecurityGroup.GroupId
30 | Export:
31 | Name: !Sub PublicAccess-${ProjectID}
32 |
33 | InternalAccess:
34 | Value: !GetAtt InternalSecurityGroup.GroupId
35 | Export:
36 | Name: !Sub InternalAccess-${ProjectID}
37 |
38 | Metadata:
39 | AWS::CloudFormation::Interface:
40 | ParameterGroups:
41 | - Label:
42 | default: Basic Configurations
43 | Parameters:
44 | - ProjectID
45 | - EdgeStackName
46 | - Label:
47 | default: Pipeline Configurations
48 | Parameters:
49 | - S3BucketName
50 | - DockerBuildImage
51 | - ApprovalEmail
52 |
53 | Parameters:
54 | ProjectID:
55 | Type: String
56 |
57 | S3BucketName:
58 | Type: String
59 |
60 | EdgeStackName:
61 | Type: String
62 |
63 | DockerBuildImage:
64 | Type: String
65 | Default: "aws/codebuild/docker:17.09.0"
66 | Description: Docker Image used by CodeBuild
67 |
68 | ApprovalEmail:
69 | Type: String
70 | Description: Email address to which approval should be sent
71 | AllowedPattern: "([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)"
72 | ConstraintDescription: Must be a valid email address. (e.g. name@example.com)
73 |
74 | Globals:
75 | Function:
76 | Runtime: nodejs8.10
77 | MemorySize: 128
78 | Timeout: 30
79 |
80 | Resources:
81 |
82 | # 成果物である Docker イメージを保持するリポジトリ
83 | DockerRepository:
84 | Type: AWS::ECR::Repository
85 | Properties:
86 | RepositoryName: fargate-handson/api
87 | LifecyclePolicy:
88 | LifecyclePolicyText: |
89 | {
90 | "rules": [
91 | {
92 | "rulePriority": 1,
93 | "description": "Only keep untagged images for 1 day",
94 | "selection": {
95 | "tagStatus": "untagged",
96 | "countType": "sinceImagePushed",
97 | "countNumber": 1,
98 | "countUnit": "days"
99 | },
100 | "action": { "type": "expire" }
101 | }
102 | ]
103 | }
104 |
105 | # ソースコードを保持するためのリポジトリ
106 | CodeRepository:
107 | Type: AWS::CodeCommit::Repository
108 | Properties:
109 | RepositoryName: fargate-handson
110 | RepositoryDescription: Code repository for Fargate hands-on
111 |
112 | # パイプラインの完了通知や承認リンクを送信するための通知トピック
113 | Topic:
114 | Type: AWS::SNS::Topic
115 | Properties:
116 | Subscription:
117 | - Protocol: email
118 | Endpoint: !Ref ApprovalEmail
119 |
120 | # 通知 Lambda の動作に必要な権限
121 | NotificationFuncRole:
122 | Type: AWS::IAM::Role
123 | Properties:
124 | AssumeRolePolicyDocument:
125 | Statement:
126 | - Effect: Allow
127 | Action: sts:AssumeRole
128 | Principal:
129 | Service: lambda.amazonaws.com
130 | Policies:
131 | - PolicyName: allow-codepipeline-and-sns
132 | PolicyDocument:
133 | Statement:
134 | - Effect: Allow
135 | Action:
136 | - codepipeline:*
137 | - sns:*
138 | Resource: "*"
139 | ManagedPolicyArns:
140 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
141 | Path: /
142 |
143 | # 通知 Lambda
144 | NotificationFunc:
145 | Type: AWS::Serverless::Function
146 | Properties:
147 | FunctionName: fargate-cicd-notification
148 | CodeUri: notification/
149 | Handler: index.handler
150 | Environment:
151 | Variables:
152 | TOPIC_ARN: !Ref Topic
153 | Role: !GetAtt NotificationFuncRole.Arn
154 |
155 | # アプリケーションのテストやビルドに必要な権限
156 | CodeBuildServiceRole:
157 | Type: AWS::IAM::Role
158 | Properties:
159 | AssumeRolePolicyDocument:
160 | Statement:
161 | - Effect: Allow
162 | Action: sts:AssumeRole
163 | Principal:
164 | Service: codebuild.amazonaws.com
165 | Policies:
166 | - PolicyName: code-build-service
167 | PolicyDocument:
168 | Statement:
169 | - Effect: Allow
170 | Action:
171 | - cloudformation:ValidateTemplate
172 | Resource: "*"
173 | - Effect: Allow
174 | Action:
175 | - logs:CreateLogGroup
176 | - logs:CreateLogStream
177 | - logs:PutLogEvents
178 | - ecr:GetAuthorizationToken
179 | Resource: "*"
180 | - Effect: Allow
181 | Action:
182 | - s3:GetObject
183 | - s3:PutObject
184 | - s3:GetObjectVersion
185 | Resource: !Sub arn:aws:s3:::${S3BucketName}/*
186 | - Effect: Allow
187 | Action:
188 | - ecr:GetDownloadUrlForLayer
189 | - ecr:BatchGetImage
190 | - ecr:BatchCheckLayerAvailability
191 | - ecr:PutImage
192 | - ecr:InitiateLayerUpload
193 | - ecr:UploadLayerPart
194 | - ecr:CompleteLayerUpload
195 | Resource: !Sub arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/${DockerRepository}
196 | Path: /
197 |
198 | # アプリケーションのテストやビルドの定義(開発環境)
199 | CodeBuild:
200 | Type: AWS::CodeBuild::Project
201 | Properties:
202 | Name: !Ref AWS::StackName
203 | ServiceRole: !Ref CodeBuildServiceRole
204 | Environment:
205 | ComputeType: BUILD_GENERAL1_SMALL
206 | Type: LINUX_CONTAINER
207 | Image: !Ref DockerBuildImage
208 | EnvironmentVariables:
209 | - Name: PROJECT_ID
210 | Value: !Ref ProjectID
211 | - Name: ENVIRONMENT_NAME
212 | Value: edge
213 | - Name: REPOSITORY_URI
214 | Value: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${DockerRepository}
215 | Artifacts:
216 | Type: CODEPIPELINE
217 | Source:
218 | Type: CODEPIPELINE
219 | BuildSpec: deploy/edge/buildspec.yml
220 |
221 | # 継続的インテグレーション/継続的デプロイのパイプラインに必要な権限
222 | CodePipelineServiceRole:
223 | Type: AWS::IAM::Role
224 | Properties:
225 | AssumeRolePolicyDocument:
226 | Statement:
227 | - Effect: Allow
228 | Action: sts:AssumeRole
229 | Principal:
230 | Service: codepipeline.amazonaws.com
231 | Policies:
232 | - PolicyName: code-pipeline-service
233 | PolicyDocument:
234 | Statement:
235 | - Effect: Allow
236 | Action:
237 | - iam:PassRole
238 | - sns:Publish
239 | - codecommit:ListRepositories
240 | - lambda:List*
241 | - cloudformation:CreateChangeSet
242 | - cloudformation:CreateStack
243 | - cloudformation:CreateUploadBucket
244 | - cloudformation:DeleteStack
245 | - cloudformation:Describe*
246 | - cloudformation:List*
247 | - cloudformation:UpdateStack
248 | - cloudformation:ValidateTemplate
249 | - cloudformation:ExecuteChangeSet
250 | Resource: "*"
251 | - Effect: Allow
252 | Action:
253 | - s3:PutObject
254 | - s3:GetObject
255 | - s3:GetObjectVersion
256 | Resource: !Sub arn:aws:s3:::${S3BucketName}/*
257 | - Effect: Allow
258 | Action:
259 | - codecommit:ListBranches
260 | - codecommit:BatchGetRepositories
261 | - codecommit:Get*
262 | - codecommit:GitPull
263 | - codecommit:UploadArchive
264 | - codecommit:CancelUploadArchive
265 | Resource:
266 | - !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${CodeRepository.Name}
267 | - Effect: Allow
268 | Action:
269 | - codebuild:StartBuild
270 | - codebuild:BatchGetBuilds
271 | Resource:
272 | - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${CodeBuild}
273 | - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:build/${CodeBuild}:*
274 | - Effect: Allow
275 | Action:
276 | - lambda:*
277 | Resource:
278 | - !GetAtt NotificationFunc.Arn
279 | Path: /
280 |
281 | # 継続的デプロイに必要な権限
282 | CloudFormationRole:
283 | Type: AWS::IAM::Role
284 | Properties:
285 | AssumeRolePolicyDocument:
286 | Statement:
287 | - Effect: Allow
288 | Action: sts:AssumeRole
289 | Principal:
290 | Service: cloudformation.amazonaws.com
291 | Policies:
292 | - PolicyName: code-pipeline-service
293 | PolicyDocument:
294 | Statement:
295 | - Effect: Allow
296 | Action:
297 | - iam:*
298 | - ecs:RegisterTaskDefinition
299 | - ecs:DeregisterTaskDefinition
300 | # for stack update / deletion
301 | - ecs:CreateService
302 | - ecs:Delete*
303 | - logs:Delete*
304 | - cloudwatch:Delete*
305 | Resource: "*"
306 | ManagedPolicyArns:
307 | - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
308 | - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceAutoscaleRole
309 | - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole
310 | Path: /
311 |
312 | # 継続的インテグレーション/継続的デプロイのパイプライン(開発環境)
313 | CodePipeline:
314 | Type: AWS::CodePipeline::Pipeline
315 | Properties:
316 | RoleArn: !GetAtt CodePipelineServiceRole.Arn
317 | ArtifactStore:
318 | Type: S3
319 | Location: !Ref S3BucketName
320 | Stages:
321 | - Name: Source
322 | Actions:
323 | - Name: Source
324 | ActionTypeId:
325 | Category: Source
326 | Provider: CodeCommit
327 | Owner: AWS
328 | Version: 1
329 | Configuration:
330 | RepositoryName: !GetAtt CodeRepository.Name
331 | BranchName: master
332 | OutputArtifacts:
333 | - Name: SourceCode
334 | RunOrder: 1
335 | - Name: Build
336 | Actions:
337 | - Name: Build
338 | ActionTypeId:
339 | Category: Build
340 | Provider: CodeBuild
341 | Owner: AWS
342 | Version: 1
343 | Configuration:
344 | ProjectName: !Ref CodeBuild
345 | InputArtifacts:
346 | - Name: SourceCode
347 | OutputArtifacts:
348 | - Name: Artifacts
349 | RunOrder: 1
350 | - Name: Deploy
351 | Actions:
352 | - Name: CreateEdgeChangeSet
353 | ActionTypeId:
354 | Category: Deploy
355 | Provider: CloudFormation
356 | Owner: AWS
357 | Version: 1
358 | Configuration:
359 | StackName: !Ref EdgeStackName
360 | ActionMode: CHANGE_SET_REPLACE
361 | ChangeSetName: ChangeSet
362 | RoleArn: !GetAtt CloudFormationRole.Arn
363 | Capabilities: CAPABILITY_NAMED_IAM
364 | TemplatePath: SourceCode::deploy/cfn-master.yaml
365 | TemplateConfiguration: Artifacts::config.json
366 | InputArtifacts:
367 | - Name: SourceCode
368 | - Name: Artifacts
369 | OutputArtifacts:
370 | - Name: CreatedEdgeChangeSet
371 | RunOrder: 1
372 | - Name: ExecuteEdgeChangeSet
373 | ActionTypeId:
374 | Category: Deploy
375 | Provider: CloudFormation
376 | Owner: AWS
377 | Version: 1
378 | Configuration:
379 | StackName: !Ref EdgeStackName
380 | ActionMode: CHANGE_SET_EXECUTE
381 | ChangeSetName: ChangeSet
382 | InputArtifacts:
383 | - Name: CreatedEdgeChangeSet
384 | OutputArtifacts:
385 | - Name: EdgeDeployed
386 | RunOrder: 2
387 | - Name: EdgeDeployedNotification
388 | ActionTypeId:
389 | Category: Invoke
390 | Provider: Lambda
391 | Owner: AWS
392 | Version: 1
393 | Configuration:
394 | FunctionName: !Ref NotificationFunc
395 | UserParameters: "{\"EnvName\":\"Edge\"}"
396 | InputArtifacts:
397 | - Name: EdgeDeployed
398 | OutputArtifacts:
399 | - Name: EdgeFinished
400 | RunOrder: 3
401 | DependsOn:
402 | - CodeBuild
403 | - CodePipelineServiceRole
404 |
405 | # アプリケーションのための VPC
406 | VPC:
407 | Type: AWS::EC2::VPC
408 | Properties:
409 | CidrBlock: 10.0.0.0/16
410 | EnableDnsSupport: true
411 | EnableDnsHostnames: true
412 | Tags:
413 | - Key: Name
414 | Value: Fargate Hands-on
415 |
416 | PublicSubnet1:
417 | Type: AWS::EC2::Subnet
418 | DependsOn: AttachGateway
419 | Properties:
420 | VpcId: !Ref VPC
421 | MapPublicIpOnLaunch: true
422 | AvailabilityZone: !Select [ 0, !GetAZs ]
423 | CidrBlock: 10.0.128.0/18
424 | Tags:
425 | - Key: Name
426 | Value: "Public Subnet 1"
427 |
428 | PublicSubnet2:
429 | Type: AWS::EC2::Subnet
430 | DependsOn: AttachGateway
431 | Properties:
432 | VpcId: !Ref VPC
433 | MapPublicIpOnLaunch: true
434 | AvailabilityZone: !Select [ 1, !GetAZs ]
435 | CidrBlock: 10.0.192.0/18
436 | Tags:
437 | - Key: Name
438 | Value: "Public Subnet 2"
439 |
440 | InternetGateway:
441 | Type: AWS::EC2::InternetGateway
442 | DependsOn: VPC
443 |
444 | AttachGateway:
445 | Type: AWS::EC2::VPCGatewayAttachment
446 | Properties:
447 | VpcId: !Ref VPC
448 | InternetGatewayId: !Ref InternetGateway
449 |
450 | PublicRouteTable:
451 | Type: AWS::EC2::RouteTable
452 | DependsOn: AttachGateway
453 | Properties:
454 | VpcId: !Ref VPC
455 | Tags:
456 | - Key: Name
457 | Value: Public
458 |
459 | PublicRoute:
460 | Type: AWS::EC2::Route
461 | DependsOn: AttachGateway
462 | Properties:
463 | RouteTableId: !Ref PublicRouteTable
464 | GatewayId: !Ref InternetGateway
465 | DestinationCidrBlock: 0.0.0.0/0
466 |
467 | PublicSubnet1RouteTableAssociation:
468 | Type: AWS::EC2::SubnetRouteTableAssociation
469 | DependsOn: AttachGateway
470 | Properties:
471 | SubnetId: !Ref PublicSubnet1
472 | RouteTableId: !Ref PublicRouteTable
473 |
474 | PublicSubnet2RouteTableAssociation:
475 | Type: AWS::EC2::SubnetRouteTableAssociation
476 | DependsOn: AttachGateway
477 | Properties:
478 | SubnetId: !Ref PublicSubnet2
479 | RouteTableId: !Ref PublicRouteTable
480 |
481 | # 一般公開からの接続用セキュリティグループ
482 | PublicAccessSecurityGroup:
483 | Type: AWS::EC2::SecurityGroup
484 | Properties:
485 | GroupDescription: SecurityGroup for load balancers
486 | VpcId: !Ref VPC
487 | SecurityGroupIngress:
488 | - IpProtocol: tcp
489 | FromPort: 80
490 | ToPort: 80
491 | CidrIp: 0.0.0.0/0
492 | Tags:
493 | - Key: Name
494 | Value: PublicAccess
495 |
496 | # VPC 内部からの接続用セキュリティグループ
497 | InternalSecurityGroup:
498 | Type: AWS::EC2::SecurityGroup
499 | Properties:
500 | GroupDescription: SecurityGroup for internal access
501 | VpcId: !Ref VPC
502 | SecurityGroupIngress:
503 | - CidrIp: 10.0.0.0/16
504 | IpProtocol: -1
505 | Tags:
506 | - Key: Name
507 | Value: InternalAccess
508 |
509 | InternalSecurityGroupIngress:
510 | Type: AWS::EC2::SecurityGroupIngress
511 | Properties:
512 | GroupId: !Ref InternalSecurityGroup
513 | IpProtocol: -1
514 | SourceSecurityGroupId: !Ref InternalSecurityGroup
515 |
--------------------------------------------------------------------------------
/fargate/notebooks/00-overview.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# ハンズオンの概要\n",
8 | "\n",
9 | "このハンズオンで実施する内容を概観します。\n",
10 | "\n",
11 | "## Jupyter notebook について\n",
12 | "\n",
13 | "[Jupyter Notebook](https://jupyter-notebook.readthedocs.io/en/stable/) はブラウザから操作のできる、Python やシェルスクリプトなどの実行環境です。 \n",
14 | "\n",
15 | "**セル**(いま左側にフォーカスがあたっていますよね?この単位がセルです)ごとに \n",
16 | "上方のメニューにある `▶︎| RUN ` でコマンドを実行することができます。\n",
17 | "\n",
18 | "`Shift + Enter` キーでも実行しながら先に進むことができます。 \n",
19 | "試しに何度か押してみましょう!"
20 | ]
21 | },
22 | {
23 | "cell_type": "code",
24 | "execution_count": null,
25 | "metadata": {},
26 | "outputs": [],
27 | "source": [
28 | "date"
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {},
34 | "source": [
35 | "応答例)\n",
36 | "```text\n",
37 | "Fri Jul 27 12:30:25 UTC 2018\n",
38 | "```"
39 | ]
40 | },
41 | {
42 | "cell_type": "code",
43 | "execution_count": null,
44 | "metadata": {},
45 | "outputs": [],
46 | "source": [
47 | "ls"
48 | ]
49 | },
50 | {
51 | "cell_type": "markdown",
52 | "metadata": {},
53 | "source": [
54 | "応答例)\n",
55 | "```text\n",
56 | "00-overview.ipynb 04-deploy-to-production.ipynb\n",
57 | "01-provision-aws-resources.ipynb 05-teardown-resources.ipynb\n",
58 | "02-develop-with-git.ipynb application\n",
59 | "03-deploy-to-staging.ipynb infrastructure\n",
60 | "```"
61 | ]
62 | },
63 | {
64 | "cell_type": "markdown",
65 | "metadata": {},
66 | "source": [
67 | "今回利用するコンテンツはすべて起動した Docker イメージの中にあり、 \n",
68 | "AWS CLI 以外の処理は **すべてコンテナの中で完結** しています。 \n",
69 | "ホスト側の環境には影響を与えませんので安心してご利用ください。 \n",
70 | "\n",
71 | "すべてのノートは画面左上の `File` からダウンロードすることもできますし \n",
72 | "`jupyter アイコン` からファイル一覧に戻り、その他のファイル操作をすることもできます。 \n",
73 | "\n",
74 | "(すべてのソースコードは [こちら](https://github.com/jawsug-container/hands-on) で公開されています)"
75 | ]
76 | },
77 | {
78 | "cell_type": "markdown",
79 | "metadata": {},
80 | "source": [
81 | "## ハンズオンと、そのサンプルケースの流れ\n",
82 | "\n",
83 | "### サンプルケース\n",
84 | "\n",
85 | "このハンズオンは、とあるアプリケーション開発者が成果物を **Fargate で公開する** ことを想定しています。 \n",
86 | "\n",
87 | "ビルド・テスト・デプロイ・リリースは極力自動化されており、以下のプロセスを経ます。\n",
88 | "\n",
89 | "1. **master ブランチに push** するとテストが走り、テストが通れば **edge** 環境にデプロイされる\n",
90 | "\n",
91 | "
\n",
92 | "\n",
93 | "2. edge 環境を実際にさわって確認\n",
94 | "3. release ブランチに対してプルリクエストを作成\n",
95 | "4. **release ブランチにマージ** されるとテストが走り、テストが通れば **staging** 環境にデプロイされる\n",
96 | "\n",
97 | "
\n",
98 | "\n",
99 | "5. staging 環境を実際にさわって確認\n",
100 | "6. **承認ボタンのクリック** で **production** 環境にリリースされる\n",
101 | "\n",
102 | "
\n",
103 | "\n",
104 | "7. production 環境を実際にさわって確認"
105 | ]
106 | },
107 | {
108 | "cell_type": "markdown",
109 | "metadata": {},
110 | "source": [
111 | "### ハンズオンの流れ\n",
112 | "\n",
113 | "サンプルケースの流れに添い、追体験をしていきます。\n",
114 | "\n",
115 | "| ノート名 | |\n",
116 | "| :-- | :-- |\n",
117 | "| 01-provision-aws-resources | 後述のシステム構成を AWS 上にプロビジョニング |\n",
118 | "| 02-develop-with-git | CodeCommit と git を使い、サンプルケースの **1, 2** を体験 |\n",
119 | "| 03-deploy-to-staging | ステージング環境を作りつつ、サンプルケースの **3, 4, 5** を体験 |\n",
120 | "| 04-deploy-to-production | 本番環境を作りつつ、サンプルケースの **6, 7** を体験 |\n",
121 | "| 05-teardown-resources | AWS リソースを掃除 |"
122 | ]
123 | },
124 | {
125 | "cell_type": "markdown",
126 | "metadata": {},
127 | "source": [
128 | "## システム構成\n",
129 | "\n",
130 | "基本的にはこうです。\n",
131 | "\n",
132 | "- Fargate (on ECS) を使って Web アプリケーションを提供\n",
133 | "- CodeCommit と CodeBuild と CloudFormation を CodePipeline で括った CI/CD パイプラインでデプロイ"
134 | ]
135 | },
136 | {
137 | "cell_type": "markdown",
138 | "metadata": {},
139 | "source": [
140 | "最終的なシステム構成は以下の通りです。\n",
141 | "\n",
142 | "
"
143 | ]
144 | },
145 | {
146 | "cell_type": "markdown",
147 | "metadata": {},
148 | "source": [
149 | "## このハンズオンに含まれていないもの\n",
150 | "\n",
151 | "通常 CI/CD にはある類のものも、ハンズオンの簡素化のため除外しています。 \n",
152 | "実際に本番稼働させるにあたっては別途十分な検討をしてください。\n",
153 | "\n",
154 | "- 本来デプロイ前後に可能な各種テスト、開発者へのフィードバック\n",
155 | "- ブランチ別のテストや PR に対してのテスト、レギュレーションの設定\n",
156 | "- 各種メトリクスやインジケータのモニタリング、通知、初期対応\n",
157 | "- イシュー・インシデントのトラック、トレース情報の収集の自動化\n",
158 | "\n",
159 | "などなど"
160 | ]
161 | },
162 | {
163 | "cell_type": "markdown",
164 | "metadata": {},
165 | "source": [
166 | "[次へ: 01-provision-aws-resources.ipynb](01-provision-aws-resources.ipynb)"
167 | ]
168 | }
169 | ],
170 | "metadata": {
171 | "kernelspec": {
172 | "display_name": "Bash",
173 | "language": "bash",
174 | "name": "bash"
175 | },
176 | "language_info": {
177 | "codemirror_mode": "shell",
178 | "file_extension": ".sh",
179 | "mimetype": "text/x-sh",
180 | "name": "bash"
181 | }
182 | },
183 | "nbformat": 4,
184 | "nbformat_minor": 2
185 | }
186 |
--------------------------------------------------------------------------------
/fargate/notebooks/03-deploy-to-staging.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# 3. 冗長構成の Fargate ステージング環境\n",
8 | "\n",
9 | "git の release ブランチへのマージで、ロードバランサを備えた評価用環境が更新される環境を作成します。\n",
10 | "\n",
11 | "## 3.1. パイプラインの改変\n",
12 | "\n",
13 | "インフラ環境更新に必要な設定値をローカルファイルに追記します。"
14 | ]
15 | },
16 | {
17 | "cell_type": "code",
18 | "execution_count": null,
19 | "metadata": {},
20 | "outputs": [],
21 | "source": [
22 | "cat << EOT >> ~/config/.env \n",
23 | "export STAGING_STACK_NAME=\"fargate-handson-staging-env\"\n",
24 | "EOT"
25 | ]
26 | },
27 | {
28 | "cell_type": "markdown",
29 | "metadata": {},
30 | "source": [
31 | "Edge 環境のリソース定義に [この](/edit/infrastructure/diff/staging) パッチをあてます。 "
32 | ]
33 | },
34 | {
35 | "cell_type": "code",
36 | "execution_count": null,
37 | "metadata": {},
38 | "outputs": [],
39 | "source": [
40 | "patch ~/notebook/infrastructure/sam.yaml < ~/notebook/infrastructure/diff/staging"
41 | ]
42 | },
43 | {
44 | "cell_type": "markdown",
45 | "metadata": {},
46 | "source": [
47 | "このテンプレートの適用により、以下のような構成へ更新していきます。 \n",
48 | "
"
49 | ]
50 | },
51 | {
52 | "cell_type": "markdown",
53 | "metadata": {},
54 | "source": [
55 | "適用前に、新しい sam.yaml の内容が正しいことを検証します。"
56 | ]
57 | },
58 | {
59 | "cell_type": "code",
60 | "execution_count": null,
61 | "metadata": {},
62 | "outputs": [],
63 | "source": [
64 | "aws cloudformation validate-template --template-body file://infrastructure/sam.yaml"
65 | ]
66 | },
67 | {
68 | "cell_type": "markdown",
69 | "metadata": {},
70 | "source": [
71 | "成功時応答例)\n",
72 | "```text\n",
73 | "{\n",
74 | " \"Description\": \"A fargate application with a CI/CD pipeline\",\n",
75 | " \"Parameters\": [\n",
76 | " {\n",
77 | " \"ParameterKey\": \"ProjectID\",\n",
78 | " \"NoEcho\": false\n",
79 | " },\n",
80 | " ..\n",
81 | "```"
82 | ]
83 | },
84 | {
85 | "cell_type": "markdown",
86 | "metadata": {},
87 | "source": [
88 | "Lambda 関数を含むテンプレートのため、パッケージングします。"
89 | ]
90 | },
91 | {
92 | "cell_type": "code",
93 | "execution_count": null,
94 | "metadata": {},
95 | "outputs": [],
96 | "source": [
97 | "source ~/config/.env\n",
98 | "\n",
99 | "aws cloudformation package \\\n",
100 | " --template-file infrastructure/sam.yaml \\\n",
101 | " --output-template-file infrastructure/cfn.yaml \\\n",
102 | " --s3-bucket \"${S3_BUCKET_NAME}\" \\\n",
103 | " --s3-prefix \"cloudformation\""
104 | ]
105 | },
106 | {
107 | "cell_type": "markdown",
108 | "metadata": {},
109 | "source": [
110 | "成功時応答)\n",
111 | "```text\n",
112 | "Uploading to cloudformation/0e64849e597b443d9a1349275098ab43 766 / 766.0 (100.00%)\n",
113 | "Successfully packaged artifacts and wrote output template to file infrastructure/cfn.yaml\n",
114 | "..\n",
115 | "```"
116 | ]
117 | },
118 | {
119 | "cell_type": "markdown",
120 | "metadata": {},
121 | "source": [
122 | "パッケージングした CloudFormation テンプレートでインフラを更新します。"
123 | ]
124 | },
125 | {
126 | "cell_type": "code",
127 | "execution_count": null,
128 | "metadata": {},
129 | "outputs": [],
130 | "source": [
131 | "aws cloudformation deploy \\\n",
132 | " --stack-name \"${BASE_STACK_NAME}\" \\\n",
133 | " --template-file infrastructure/cfn.yaml \\\n",
134 | " --parameter-overrides \\\n",
135 | " ProjectID=\"${PROJECT_ID}\" \\\n",
136 | " S3BucketName=\"${S3_BUCKET_NAME}\" \\\n",
137 | " EdgeStackName=\"${EDGE_STACK_NAME}\" \\\n",
138 | " StagingStackName=\"${STAGING_STACK_NAME}\" \\\n",
139 | " ApprovalEmail=\"${GIT_EMAIL_ADDRESS}\" \\\n",
140 | " --capabilities CAPABILITY_IAM"
141 | ]
142 | },
143 | {
144 | "cell_type": "markdown",
145 | "metadata": {},
146 | "source": [
147 | "成功時応答)\n",
148 | "```text\n",
149 | "Waiting for changeset to be created..\n",
150 | "Waiting for stack create/update to complete\n",
151 | "Successfully created/updated stack - fargate-handson-base\n",
152 | "```"
153 | ]
154 | },
155 | {
156 | "cell_type": "markdown",
157 | "metadata": {},
158 | "source": [
159 | "## 3.2. ステージング環境の Fargate を起動する\n",
160 | "\n",
161 | "[こちら](/edit/application/deploy/cfn-release.yaml) のテンプレートを使い、ステージング環境を作成します。 \n",
162 | "この環境はロードバランサーやオートスケーリングの設定がされ、本番環境を想定した構成になっています。\n",
163 | "\n",
164 | "```\n",
165 | "- CloudWatch Logs ロググループ\n",
166 | "- ECS クラスター\n",
167 | "- ECS タスク定義\n",
168 | "- ECS サービス\n",
169 | "- IAM ロール * 2\n",
170 | "```\n",
171 | "\n",
172 | "TODO: 図を用意する\n",
173 | "\n",
174 | "開発環境 Fargate とステージング・本番環境 Fargate の差分を確認してみます。"
175 | ]
176 | },
177 | {
178 | "cell_type": "code",
179 | "execution_count": null,
180 | "metadata": {},
181 | "outputs": [],
182 | "source": [
183 | "diff ~/notebook/application/deploy/cfn-master.yaml \\\n",
184 | " ~/notebook/application/deploy/cfn-release.yaml"
185 | ]
186 | },
187 | {
188 | "cell_type": "markdown",
189 | "metadata": {},
190 | "source": [
191 | "では実際にステージング環境の Fargate をデプロイしてみます。"
192 | ]
193 | },
194 | {
195 | "cell_type": "code",
196 | "execution_count": null,
197 | "metadata": {},
198 | "outputs": [],
199 | "source": [
200 | "DOCKER_IMAGE=dockercloud/hello-world\n",
201 | "\n",
202 | "aws cloudformation deploy \\\n",
203 | " --stack-name \"${STAGING_STACK_NAME}\" \\\n",
204 | " --template-file application/deploy/cfn-release.yaml \\\n",
205 | " --parameter-overrides \\\n",
206 | " ProjectID=\"${PROJECT_ID}\" \\\n",
207 | " DockerImage=\"${DOCKER_IMAGE}\" \\\n",
208 | " --capabilities CAPABILITY_IAM"
209 | ]
210 | },
211 | {
212 | "cell_type": "markdown",
213 | "metadata": {},
214 | "source": [
215 | "成功時応答)\n",
216 | "```text\n",
217 | "Waiting for changeset to be created..\n",
218 | "Waiting for stack create/update to complete\n",
219 | "Successfully created/updated stack - fargate-handson-staging-env\n",
220 | "```"
221 | ]
222 | },
223 | {
224 | "cell_type": "markdown",
225 | "metadata": {},
226 | "source": [
227 | "構築が完了したら、ステージング環境の Fargate を確認してみましょう。"
228 | ]
229 | },
230 | {
231 | "cell_type": "code",
232 | "execution_count": null,
233 | "metadata": {},
234 | "outputs": [],
235 | "source": [
236 | "STAGING_ENDPOINT=\"http://$( aws cloudformation describe-stacks \\\n",
237 | " --stack-name \"${STAGING_STACK_NAME}\" --output text \\\n",
238 | " --query 'Stacks[*].Outputs[?OutputKey==`LoadBalancerDNSName`].OutputValue' )\"\n",
239 | "\n",
240 | "cat << EOT >> ~/config/.env\n",
241 | "export STAGING_ENDPOINT=\"${STAGING_ENDPOINT}\"\n",
242 | "EOT\n",
243 | "echo \"${STAGING_ENDPOINT}\""
244 | ]
245 | },
246 | {
247 | "cell_type": "markdown",
248 | "metadata": {},
249 | "source": [
250 | "応答例)\n",
251 | "```text\n",
252 | "http://farga-LoadB-xxx-xxx.ap-northeast-1.elb.amazonaws.com\n",
253 | "```"
254 | ]
255 | },
256 | {
257 | "cell_type": "markdown",
258 | "metadata": {},
259 | "source": [
260 | "ロードバランサー経由で Fargate にアクセスできましたか? \n",
261 | "オートスケーリングの設定もされており、これで負荷分散する Fargate の完成です。"
262 | ]
263 | },
264 | {
265 | "cell_type": "markdown",
266 | "metadata": {},
267 | "source": [
268 | "## 3.3. リリースブランチへのマージでステージング環境を更新する\n",
269 | "\n",
270 | "CodeCommit に現在の master ブランチから release ブランチを作り、ステージング環境も更新しましょう。"
271 | ]
272 | },
273 | {
274 | "cell_type": "code",
275 | "execution_count": null,
276 | "metadata": {},
277 | "outputs": [],
278 | "source": [
279 | "cd ~/notebook/application\n",
280 | "git log -1\n",
281 | "\n",
282 | "aws codecommit create-branch \\\n",
283 | " --repository-name \"fargate-handson\" \\\n",
284 | " --branch-name \"release\" \\\n",
285 | " --commit-id \"$( git log -1 --pretty=%H )\""
286 | ]
287 | },
288 | {
289 | "cell_type": "markdown",
290 | "metadata": {},
291 | "source": [
292 | "応答例)\n",
293 | "```text\n",
294 | "commit 2236df05287049512148f204395f0d433c47a382 (HEAD -> master, origin/master)\n",
295 | "Author: foo \n",
296 | "Date: Mon Jul 23 13:24:04 2018 +0000\n",
297 | "\n",
298 | " first commit\n",
299 | "```"
300 | ]
301 | },
302 | {
303 | "cell_type": "markdown",
304 | "metadata": {},
305 | "source": [
306 | "CodePipeline のコンソールから、**リリース版パイプライン** が更新されるのを眺めます。"
307 | ]
308 | },
309 | {
310 | "cell_type": "code",
311 | "execution_count": null,
312 | "metadata": {},
313 | "outputs": [],
314 | "source": [
315 | "codebuild_project_name=$( aws cloudformation describe-stacks \\\n",
316 | " --stack-name \"${BASE_STACK_NAME}\" --output text \\\n",
317 | " --query 'Stacks[*].Outputs[?OutputKey==`CodePipelineRelease`].OutputValue' )\n",
318 | "codebuild_console=\"https://ap-northeast-1.console.aws.amazon.com/codepipeline/home\"\n",
319 | "echo \"${codebuild_console}?region=${AWS_DEFAULT_REGION}#/view/${codebuild_project_name}\""
320 | ]
321 | },
322 | {
323 | "cell_type": "markdown",
324 | "metadata": {},
325 | "source": [
326 | "更新されたら、Fargate の内容が新しくなっていることを確認しましょう。"
327 | ]
328 | },
329 | {
330 | "cell_type": "code",
331 | "execution_count": null,
332 | "metadata": {},
333 | "outputs": [],
334 | "source": [
335 | "echo \"${STAGING_ENDPOINT}\""
336 | ]
337 | },
338 | {
339 | "cell_type": "markdown",
340 | "metadata": {},
341 | "source": [
342 | "## 3.4. プルリクエストで環境を更新する\n",
343 | "\n",
344 | "master を更新し、release に対しプルリクを作成し、マージされることでも同様の環境更新がされることを確認します。\n",
345 | "\n",
346 | "### 3.4.1. アプリケーション定義の書き換え、master へ push\n",
347 | "\n",
348 | "- Dockerfile を書き換え、ip-api.com へのリバースプロキシを Fargate で動かします\n",
349 | "- Basic 認証がかかるよう、CodeBuild 経由で cfn.yaml に渡す環境変数をセットします\n",
350 | "\n",
351 | "ここまでを git commit -> push します。"
352 | ]
353 | },
354 | {
355 | "cell_type": "code",
356 | "execution_count": null,
357 | "metadata": {
358 | "scrolled": false
359 | },
360 | "outputs": [],
361 | "source": [
362 | "cd ~/notebook/application\n",
363 | "\n",
364 | "cat << EOF > Dockerfile\n",
365 | "FROM pottava/proxy\n",
366 | "\n",
367 | "ENV APP_PORT=80 \\\\\n",
368 | " PROXY_PATTERNS=\"*=http://ip-api.com/json\" \\\\\n",
369 | " HEALTHCHECK_PATH=/health \\\\\n",
370 | " ACCESS_LOG=true\n",
371 | "EOF\n",
372 | "\n",
373 | "cat << EOT > deploy/edge/env.sh\n",
374 | "export BASIC_AUTH=\"BasicAuthUsername\":\"edge\",\"BasicAuthPassword\":\"fargate\"\n",
375 | "EOT\n",
376 | "chmod +x deploy/edge/env.sh\n",
377 | "cat << EOT > deploy/staging/env.sh\n",
378 | "export BASIC_AUTH=\"BasicAuthUsername\":\"staging\",\"BasicAuthPassword\":\"fargate\"\n",
379 | "EOT\n",
380 | "chmod +x deploy/staging/env.sh\n",
381 | "\n",
382 | "git add .\n",
383 | "git commit -m \"reverse-proxy to ip-api.com\"\n",
384 | "git push"
385 | ]
386 | },
387 | {
388 | "cell_type": "markdown",
389 | "metadata": {},
390 | "source": [
391 | "応答例)\n",
392 | "```text\n",
393 | "[master 628191e] reverse-proxy to ip-api.com\n",
394 | " 2 files changed, 2 insertions(+), 2 deletions(-)\n",
395 | "Counting objects: 7, done.\n",
396 | "..\n",
397 | "```"
398 | ]
399 | },
400 | {
401 | "cell_type": "markdown",
402 | "metadata": {},
403 | "source": [
404 | "開発(Edge)環境のパイプラインが動き、環境が更新されます。 \n",
405 | "内容が正しそうか確認しましょう。"
406 | ]
407 | },
408 | {
409 | "cell_type": "code",
410 | "execution_count": null,
411 | "metadata": {},
412 | "outputs": [],
413 | "source": [
414 | "codebuild_project_name=$( aws cloudformation describe-stacks \\\n",
415 | " --stack-name \"${BASE_STACK_NAME}\" --output text \\\n",
416 | " --query 'Stacks[*].Outputs[?OutputKey==`CodePipeline`].OutputValue' )\n",
417 | "codebuild_console=\"https://ap-northeast-1.console.aws.amazon.com/codepipeline/home\"\n",
418 | "echo \"${codebuild_console}?region=${AWS_DEFAULT_REGION}#/view/${codebuild_project_name}\""
419 | ]
420 | },
421 | {
422 | "cell_type": "code",
423 | "execution_count": null,
424 | "metadata": {},
425 | "outputs": [],
426 | "source": [
427 | "cluster_name=$( aws cloudformation describe-stacks \\\n",
428 | " --stack-name \"${EDGE_STACK_NAME}\" --output text \\\n",
429 | " --query 'Stacks[*].Outputs[?OutputKey==`Cluster`].OutputValue' )\n",
430 | "task_id=$( aws ecs list-tasks --cluster \"${cluster_name}\" \\\n",
431 | " --family \"${EDGE_STACK_NAME}\" | jq -r '.taskArns[0]' )\n",
432 | "eni_id=$( aws ecs describe-tasks --cluster \"${cluster_name}\" --task \"${task_id}\" \\\n",
433 | " | jq '.tasks[0].attachments[0].details[]' \\\n",
434 | " | jq -r 'select( .name | contains(\"networkInterfaceId\")).value' )\n",
435 | "edge_endpoint=\"http://$( aws ec2 describe-network-interfaces \\\n",
436 | " --network-interface-ids ${eni_id} \\\n",
437 | " | jq -r '.NetworkInterfaces[].Association.PublicIp' )\"\n",
438 | "\n",
439 | "echo \"${edge_endpoint}/json\""
440 | ]
441 | },
442 | {
443 | "cell_type": "markdown",
444 | "metadata": {},
445 | "source": [
446 | "Basic 認証は上記変更の通り、ユーザー名は **edge**、パスワードは **fargate** です。\n",
447 | "\n",
448 | "ブラウザでアクセスすると、以下のような JSON か返ってくるかと思います。 \n",
449 | "応答例)\n",
450 | "```\n",
451 | "{\n",
452 | " as: \"AS16509 Amazon.com, Inc.\",\n",
453 | " countryCode: \"JP\",\n",
454 | " city: \"Tokyo\",\n",
455 | " country: \"Japan\",\n",
456 | " isp: \"Amazon.com\",\n",
457 | " query: \"13.115.178.180\",\n",
458 | " ..\n",
459 | "}\n",
460 | "```"
461 | ]
462 | },
463 | {
464 | "cell_type": "markdown",
465 | "metadata": {},
466 | "source": [
467 | "Edge 環境で動作確認が取れたら、release ブランチに対してプルリクエストを作成します。"
468 | ]
469 | },
470 | {
471 | "cell_type": "code",
472 | "execution_count": null,
473 | "metadata": {},
474 | "outputs": [],
475 | "source": [
476 | "repo=\"fargate-handson\"\n",
477 | "aws codecommit create-pull-request \\\n",
478 | " --title \"My first Pull Request\" \\\n",
479 | " --description \"Please review this immediately!\" \\\n",
480 | " --targets \"repositoryName=${repo},sourceReference=master,destinationReference=release\""
481 | ]
482 | },
483 | {
484 | "cell_type": "markdown",
485 | "metadata": {},
486 | "source": [
487 | "応答例)\n",
488 | "```text\n",
489 | "{\n",
490 | " \"pullRequest\": {\n",
491 | " \"pullRequestId\": \"1\",\n",
492 | " \"title\": \"My first Pull Request\",\n",
493 | " \"description\": \"Please review this immediately!\",\n",
494 | " \"pullRequestTargets\": [\n",
495 | " {\n",
496 | " \"repositoryName\": \"fargate-handson\",\n",
497 | " \"sourceReference\": \"refs/heads/master\",\n",
498 | " \"destinationReference\": \"refs/heads/release\",\n",
499 | " ..\n",
500 | "}\n",
501 | "```"
502 | ]
503 | },
504 | {
505 | "cell_type": "markdown",
506 | "metadata": {},
507 | "source": [
508 | "残念ながら、孤独に一人で開発中なので、自分でレビューをしてマージしましょう・・ \n",
509 | "https://ap-northeast-1.console.aws.amazon.com/codecommit/home?region=ap-northeast-1#/repository/fargate-handson/pull-requests"
510 | ]
511 | },
512 | {
513 | "cell_type": "markdown",
514 | "metadata": {},
515 | "source": [
516 | "release ブランチにマージされると、ステージング環境へのデプロイが開始されます。"
517 | ]
518 | },
519 | {
520 | "cell_type": "code",
521 | "execution_count": null,
522 | "metadata": {},
523 | "outputs": [],
524 | "source": [
525 | "codebuild_project_name=$( aws cloudformation describe-stacks \\\n",
526 | " --stack-name \"${BASE_STACK_NAME}\" --output text \\\n",
527 | " --query 'Stacks[*].Outputs[?OutputKey==`CodePipelineRelease`].OutputValue' )\n",
528 | "codebuild_console=\"https://ap-northeast-1.console.aws.amazon.com/codepipeline/home\"\n",
529 | "echo \"${codebuild_console}?region=${AWS_DEFAULT_REGION}#/view/${codebuild_project_name}\""
530 | ]
531 | },
532 | {
533 | "cell_type": "markdown",
534 | "metadata": {},
535 | "source": [
536 | "ステージング環境でも内容が変更されたことを確認してみましょう。"
537 | ]
538 | },
539 | {
540 | "cell_type": "code",
541 | "execution_count": null,
542 | "metadata": {
543 | "scrolled": true
544 | },
545 | "outputs": [],
546 | "source": [
547 | "echo \"${STAGING_ENDPOINT}/json\""
548 | ]
549 | },
550 | {
551 | "cell_type": "markdown",
552 | "metadata": {},
553 | "source": [
554 | "Basic 認証のユーザー名は **staging**、パスワードは **fargate** です。\n",
555 | "\n",
556 | "開発環境同様、以下のような JSON か返ってくれば OK です! \n",
557 | "応答例)\n",
558 | "```\n",
559 | "{\n",
560 | " as: \"AS16509 Amazon.com, Inc.\",\n",
561 | " countryCode: \"JP\",\n",
562 | " city: \"Tokyo\",\n",
563 | " country: \"Japan\",\n",
564 | " isp: \"Amazon.com\",\n",
565 | " query: \"13.115.178.180\",\n",
566 | " ..\n",
567 | "}\n",
568 | "```"
569 | ]
570 | },
571 | {
572 | "cell_type": "markdown",
573 | "metadata": {},
574 | "source": [
575 | "[次へ: 04-deploy-to-production.ipynb](04-deploy-to-production.ipynb)"
576 | ]
577 | }
578 | ],
579 | "metadata": {
580 | "kernelspec": {
581 | "display_name": "Bash",
582 | "language": "bash",
583 | "name": "bash"
584 | },
585 | "language_info": {
586 | "codemirror_mode": "shell",
587 | "file_extension": ".sh",
588 | "mimetype": "text/x-sh",
589 | "name": "bash"
590 | }
591 | },
592 | "nbformat": 4,
593 | "nbformat_minor": 2
594 | }
595 |
--------------------------------------------------------------------------------
/fargate/notebooks/05-teardown-resources.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# 5. AWS リソースの削除\n",
8 | "\n",
9 | "## 5.1. Production 環境のサービス停止\n",
10 | "\n",
11 | "CloudFormation スタックが更新中や停止中の場合削除に失敗します。 \n",
12 | "すべて正常に処理が終了することを確認しながら進めてください!"
13 | ]
14 | },
15 | {
16 | "cell_type": "code",
17 | "execution_count": null,
18 | "metadata": {},
19 | "outputs": [],
20 | "source": [
21 | "source ~/config/.env\n",
22 | "\n",
23 | "aws cloudformation delete-stack --stack-name \"${PRODUCTION_STACK_NAME}\"\n",
24 | "aws cloudformation wait stack-delete-complete --stack-name \"${PRODUCTION_STACK_NAME}\""
25 | ]
26 | },
27 | {
28 | "cell_type": "markdown",
29 | "metadata": {},
30 | "source": [
31 | "## 5.3. Staging 環境のサービス停止"
32 | ]
33 | },
34 | {
35 | "cell_type": "code",
36 | "execution_count": null,
37 | "metadata": {},
38 | "outputs": [],
39 | "source": [
40 | "aws cloudformation delete-stack --stack-name \"${STAGING_STACK_NAME}\"\n",
41 | "aws cloudformation wait stack-delete-complete --stack-name \"${STAGING_STACK_NAME}\""
42 | ]
43 | },
44 | {
45 | "cell_type": "markdown",
46 | "metadata": {},
47 | "source": [
48 | "## 5.3. Edge 環境のサービス停止"
49 | ]
50 | },
51 | {
52 | "cell_type": "code",
53 | "execution_count": null,
54 | "metadata": {},
55 | "outputs": [],
56 | "source": [
57 | "aws cloudformation delete-stack --stack-name \"${EDGE_STACK_NAME}\"\n",
58 | "aws cloudformation wait stack-delete-complete --stack-name \"${EDGE_STACK_NAME}\""
59 | ]
60 | },
61 | {
62 | "cell_type": "markdown",
63 | "metadata": {},
64 | "source": [
65 | "成功時応答)\n",
66 | "```text\n",
67 | "なし\n",
68 | "```"
69 | ]
70 | },
71 | {
72 | "cell_type": "markdown",
73 | "metadata": {},
74 | "source": [
75 | "## 5.4. ECR リポジトリの削除"
76 | ]
77 | },
78 | {
79 | "cell_type": "code",
80 | "execution_count": null,
81 | "metadata": {},
82 | "outputs": [],
83 | "source": [
84 | "aws ecr delete-repository --repository-name fargate-handson/api --force"
85 | ]
86 | },
87 | {
88 | "cell_type": "markdown",
89 | "metadata": {},
90 | "source": [
91 | "成功時応答例)\n",
92 | "```text\n",
93 | "{\n",
94 | " \"repository\": {\n",
95 | " \"repositoryArn\": \"arn:aws:ecr:ap-northeast-1:xxx:repository/fargate-handson/api\",\n",
96 | " \"registryId\": \"111111111111\",\n",
97 | " ..\n",
98 | " }\n",
99 | "}\n",
100 | "```"
101 | ]
102 | },
103 | {
104 | "cell_type": "markdown",
105 | "metadata": {},
106 | "source": [
107 | "## 5.5. VPC や CI/CD パイプラインの削除"
108 | ]
109 | },
110 | {
111 | "cell_type": "code",
112 | "execution_count": null,
113 | "metadata": {},
114 | "outputs": [],
115 | "source": [
116 | "aws cloudformation delete-stack --stack-name \"${BASE_STACK_NAME}\"\n",
117 | "aws cloudformation wait stack-delete-complete --stack-name \"${BASE_STACK_NAME}\""
118 | ]
119 | },
120 | {
121 | "cell_type": "markdown",
122 | "metadata": {},
123 | "source": [
124 | "成功時応答)\n",
125 | "```text\n",
126 | "なし\n",
127 | "```"
128 | ]
129 | },
130 | {
131 | "cell_type": "markdown",
132 | "metadata": {},
133 | "source": [
134 | "## 5.6. S3 バケットの削除"
135 | ]
136 | },
137 | {
138 | "cell_type": "code",
139 | "execution_count": null,
140 | "metadata": {},
141 | "outputs": [],
142 | "source": [
143 | "aws s3 rb \"s3://${S3_BUCKET_NAME}\" --force"
144 | ]
145 | },
146 | {
147 | "cell_type": "markdown",
148 | "metadata": {},
149 | "source": [
150 | "成功時応答)\n",
151 | "```text\n",
152 | "..\n",
153 | "delete: s3://fargate-handson-56333cb5-a2d0-442d-92fb-4e26f9b5a3dc/fargate-handson-base/Artifacts/qncICBP\n",
154 | "delete: s3://fargate-handson-56333cb5-a2d0-442d-92fb-4e26f9b5a3dc/fargate-handson-base/SourceCode/iGJNnsS\n",
155 | "remove_bucket: fargate-handson-56333cb5-a2d0-442d-92fb-4e26f9b5a3dc\n",
156 | "```"
157 | ]
158 | },
159 | {
160 | "cell_type": "markdown",
161 | "metadata": {},
162 | "source": [
163 | "## 5.7. CloudWatch Logs の削除"
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": null,
169 | "metadata": {
170 | "scrolled": true
171 | },
172 | "outputs": [],
173 | "source": [
174 | "aws logs delete-log-group --log-group-name /aws/codebuild/fargate-handson-base\n",
175 | "aws logs delete-log-group --log-group-name /aws/codebuild/fargate-handson-base-staging\n",
176 | "aws logs delete-log-group --log-group-name /aws/codebuild/fargate-handson-base-production\n",
177 | "aws logs delete-log-group --log-group-name /aws/lambda/fargate-cicd-notification"
178 | ]
179 | },
180 | {
181 | "cell_type": "markdown",
182 | "metadata": {},
183 | "source": [
184 | "成功時応答)\n",
185 | "```text\n",
186 | "なし\n",
187 | "```"
188 | ]
189 | },
190 | {
191 | "cell_type": "markdown",
192 | "metadata": {},
193 | "source": [
194 | "最後までお付き合いいただきありがとうございました。 \n",
195 | "ハンズオンは以上です!"
196 | ]
197 | }
198 | ],
199 | "metadata": {
200 | "kernelspec": {
201 | "display_name": "Bash",
202 | "language": "bash",
203 | "name": "bash"
204 | },
205 | "language_info": {
206 | "codemirror_mode": "shell",
207 | "file_extension": ".sh",
208 | "mimetype": "text/x-sh",
209 | "name": "bash"
210 | }
211 | },
212 | "nbformat": 4,
213 | "nbformat_minor": 2
214 | }
215 |
--------------------------------------------------------------------------------
/fargate/notebooks/notebook-assets/app-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawsug-container/hands-on/367d71fff56c203040280ca742e4d5a4b58211ee/fargate/notebooks/notebook-assets/app-1.png
--------------------------------------------------------------------------------
/fargate/notebooks/notebook-assets/infra-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawsug-container/hands-on/367d71fff56c203040280ca742e4d5a4b58211ee/fargate/notebooks/notebook-assets/infra-1.png
--------------------------------------------------------------------------------
/fargate/notebooks/notebook-assets/infra-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawsug-container/hands-on/367d71fff56c203040280ca742e4d5a4b58211ee/fargate/notebooks/notebook-assets/infra-2.png
--------------------------------------------------------------------------------
/fargate/notebooks/notebook-assets/whole-arch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawsug-container/hands-on/367d71fff56c203040280ca742e4d5a4b58211ee/fargate/notebooks/notebook-assets/whole-arch.png
--------------------------------------------------------------------------------
/fargate/notebooks/notebook-assets/workflow-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawsug-container/hands-on/367d71fff56c203040280ca742e4d5a4b58211ee/fargate/notebooks/notebook-assets/workflow-1.png
--------------------------------------------------------------------------------
/fargate/notebooks/notebook-assets/workflow-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawsug-container/hands-on/367d71fff56c203040280ca742e4d5a4b58211ee/fargate/notebooks/notebook-assets/workflow-2.png
--------------------------------------------------------------------------------
/fargate/notebooks/notebook-assets/workflow-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawsug-container/hands-on/367d71fff56c203040280ca742e4d5a4b58211ee/fargate/notebooks/notebook-assets/workflow-3.png
--------------------------------------------------------------------------------
/fargate/notebooks_config/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function usage() {
4 | set -e
5 | cat </dev/null )
68 | ret="$?"
69 | if [ "${identity}" = "" ]; then
70 | echo "AWS アクセスキーが不正です"
71 | exit "${ret}"
72 | fi
73 |
74 | versions=$( docker version )
75 | ret="$?"
76 | if [ "${ret}" != "0" ]; then
77 | echo "Docker ホストとの通信に問題があります"
78 | exit "${ret}"
79 | fi
80 |
81 | if [ ! -e /root/config/.env ]; then
82 | cat << EOF > /root/config/.env
83 | export PROJECT_ID=$( python3 -c "import uuid;print(uuid.uuid4())" )
84 | EOF
85 | fi
86 | # shellcheck disable=SC1091
87 | source /root/config/.env
88 |
89 | cat << EOT
90 |
91 | ProjectID: ${PROJECT_ID}
92 |
93 | [ AWS 環境情報 ]
94 |
95 | Account: $( echo "${identity}" | jq -r '.Account' )
96 | Region: ${AWS_DEFAULT_REGION}
97 | IAM User: $( echo "${identity}" | jq -r '.Arn' )
98 | AccessKey: $( echo "${identity}" | jq -r '.UserId' )
99 |
100 | [ Git 情報 ]
101 |
102 | UserName: ${GIT_USER_NAME}
103 | Email: ${GIT_EMAIL_ADDRESS}
104 |
105 | [ Docker 情報 ]
106 |
107 | ClientVer: $( echo "${versions}" | yq -r '.Client.Version' )
108 | ServerVer: $( echo "${versions}" | yq -r '.Server.Engine.Version' )
109 |
110 | EOT
111 |
112 | exec "$@"
113 |
--------------------------------------------------------------------------------
/fargate/notebooks_config/jupyter_notebook.py:
--------------------------------------------------------------------------------
1 | # Configuration file for jupyter-notebook.
2 |
3 | #------------------------------------------------------------------------------
4 | # Application(SingletonConfigurable) configuration
5 | #------------------------------------------------------------------------------
6 |
7 | ## This is an application.
8 |
9 | ## The date format used by logging formatters for %(asctime)s
10 | #c.Application.log_datefmt = '%Y-%m-%d %H:%M:%S'
11 |
12 | ## The Logging format template
13 | #c.Application.log_format = '[%(name)s]%(highlevel)s %(message)s'
14 |
15 | ## Set the log level by value or name.
16 | #c.Application.log_level = 30
17 |
18 | #------------------------------------------------------------------------------
19 | # JupyterApp(Application) configuration
20 | #------------------------------------------------------------------------------
21 |
22 | ## Base class for Jupyter applications
23 |
24 | ## Answer yes to any prompts.
25 | #c.JupyterApp.answer_yes = False
26 |
27 | ## Full path of a config file.
28 | #c.JupyterApp.config_file = ''
29 |
30 | ## Specify a config file to load.
31 | #c.JupyterApp.config_file_name = ''
32 |
33 | ## Generate default config file.
34 | #c.JupyterApp.generate_config = False
35 |
36 | #------------------------------------------------------------------------------
37 | # NotebookApp(JupyterApp) configuration
38 | #------------------------------------------------------------------------------
39 |
40 | ## Set the Access-Control-Allow-Credentials: true header
41 | #c.NotebookApp.allow_credentials = False
42 |
43 | ## Set the Access-Control-Allow-Origin header
44 | #
45 | # Use '*' to allow any origin to access your server.
46 | #
47 | # Takes precedence over allow_origin_pat.
48 | #c.NotebookApp.allow_origin = ''
49 |
50 | ## Use a regular expression for the Access-Control-Allow-Origin header
51 | #
52 | # Requests from an origin matching the expression will get replies with:
53 | #
54 | # Access-Control-Allow-Origin: origin
55 | #
56 | # where `origin` is the origin of the request.
57 | #
58 | # Ignored if allow_origin is set.
59 | #c.NotebookApp.allow_origin_pat = ''
60 |
61 | ## Allow password to be changed at login for the notebook server.
62 | #
63 | # While loggin in with a token, the notebook server UI will give the opportunity
64 | # to the user to enter a new password at the same time that will replace the
65 | # token login mechanism.
66 | #
67 | # This can be set to false to prevent changing password from the UI/API.
68 | #c.NotebookApp.allow_password_change = True
69 |
70 | ## Whether to allow the user to run the notebook as root.
71 | #c.NotebookApp.allow_root = False
72 | c.NotebookApp.allow_root = True
73 |
74 | ## DEPRECATED use base_url
75 | #c.NotebookApp.base_project_url = '/'
76 |
77 | ## The base URL for the notebook server.
78 | #
79 | # Leading and trailing slashes can be omitted, and will automatically be added.
80 | #c.NotebookApp.base_url = '/'
81 |
82 | ## Specify what command to use to invoke a web browser when opening the notebook.
83 | # If not specified, the default browser will be determined by the `webbrowser`
84 | # standard library module, which allows setting of the BROWSER environment
85 | # variable to override it.
86 | #c.NotebookApp.browser = ''
87 |
88 | ## The full path to an SSL/TLS certificate file.
89 | #c.NotebookApp.certfile = ''
90 |
91 | ## The full path to a certificate authority certificate for SSL/TLS client
92 | # authentication.
93 | #c.NotebookApp.client_ca = ''
94 |
95 | ## The config manager class to use
96 | #c.NotebookApp.config_manager_class = 'notebook.services.config.manager.ConfigManager'
97 |
98 | ## The notebook manager class to use.
99 | #c.NotebookApp.contents_manager_class = 'notebook.services.contents.largefilemanager.LargeFileManager'
100 |
101 | ## Extra keyword arguments to pass to `set_secure_cookie`. See tornado's
102 | # set_secure_cookie docs for details.
103 | #c.NotebookApp.cookie_options = {}
104 |
105 | ## The random bytes used to secure cookies. By default this is a new random
106 | # number every time you start the Notebook. Set it to a value in a config file
107 | # to enable logins to persist across server sessions.
108 | #
109 | # Note: Cookie secrets should be kept private, do not share config files with
110 | # cookie_secret stored in plaintext (you can read the value from a file).
111 | #c.NotebookApp.cookie_secret = b''
112 |
113 | ## The file where the cookie secret is stored.
114 | #c.NotebookApp.cookie_secret_file = ''
115 |
116 | ## The default URL to redirect to from `/`
117 | #c.NotebookApp.default_url = '/tree'
118 |
119 | ## Disable cross-site-request-forgery protection
120 | #
121 | # Jupyter notebook 4.3.1 introduces protection from cross-site request
122 | # forgeries, requiring API requests to either:
123 | #
124 | # - originate from pages served by this server (validated with XSRF cookie and
125 | # token), or - authenticate with a token
126 | #
127 | # Some anonymous compute resources still desire the ability to run code,
128 | # completely without authentication. These services can disable all
129 | # authentication and security checks, with the full knowledge of what that
130 | # implies.
131 | #c.NotebookApp.disable_check_xsrf = False
132 |
133 | ## Whether to enable MathJax for typesetting math/TeX
134 | #
135 | # MathJax is the javascript library Jupyter uses to render math/LaTeX. It is
136 | # very large, so you may want to disable it if you have a slow internet
137 | # connection, or for offline use of the notebook.
138 | #
139 | # When disabled, equations etc. will appear as their untransformed TeX source.
140 | #c.NotebookApp.enable_mathjax = True
141 |
142 | ## extra paths to look for Javascript notebook extensions
143 | #c.NotebookApp.extra_nbextensions_path = []
144 |
145 | ## handlers that should be loaded at higher priority than the default services
146 | #c.NotebookApp.extra_services = []
147 |
148 | ## Extra paths to search for serving static files.
149 | #
150 | # This allows adding javascript/css to be available from the notebook server
151 | # machine, or overriding individual files in the IPython
152 | #c.NotebookApp.extra_static_paths = []
153 |
154 | ## Extra paths to search for serving jinja templates.
155 | #
156 | # Can be used to override templates from notebook.templates.
157 | #c.NotebookApp.extra_template_paths = []
158 |
159 | ##
160 | #c.NotebookApp.file_to_run = ''
161 |
162 | ## Deprecated: Use minified JS file or not, mainly use during dev to avoid JS
163 | # recompilation
164 | #c.NotebookApp.ignore_minified_js = False
165 |
166 | ## (bytes/sec) Maximum rate at which stream output can be sent on iopub before
167 | # they are limited.
168 | #c.NotebookApp.iopub_data_rate_limit = 1000000
169 |
170 | ## (msgs/sec) Maximum rate at which messages can be sent on iopub before they are
171 | # limited.
172 | #c.NotebookApp.iopub_msg_rate_limit = 1000
173 |
174 | ## The IP address the notebook server will listen on.
175 | #c.NotebookApp.ip = 'localhost'
176 | c.NotebookApp.ip = '0.0.0.0'
177 |
178 | ## Supply extra arguments that will be passed to Jinja environment.
179 | #c.NotebookApp.jinja_environment_options = {}
180 |
181 | ## Extra variables to supply to jinja templates when rendering.
182 | #c.NotebookApp.jinja_template_vars = {}
183 |
184 | ## The kernel manager class to use.
185 | #c.NotebookApp.kernel_manager_class = 'notebook.services.kernels.kernelmanager.MappingKernelManager'
186 |
187 | ## The kernel spec manager class to use. Should be a subclass of
188 | # `jupyter_client.kernelspec.KernelSpecManager`.
189 | #
190 | # The Api of KernelSpecManager is provisional and might change without warning
191 | # between this version of Jupyter and the next stable one.
192 | #c.NotebookApp.kernel_spec_manager_class = 'jupyter_client.kernelspec.KernelSpecManager'
193 |
194 | ## The full path to a private key file for usage with SSL/TLS.
195 | #c.NotebookApp.keyfile = ''
196 |
197 | ## The login handler class to use.
198 | #c.NotebookApp.login_handler_class = 'notebook.auth.login.LoginHandler'
199 |
200 | ## The logout handler class to use.
201 | #c.NotebookApp.logout_handler_class = 'notebook.auth.logout.LogoutHandler'
202 |
203 | ## The MathJax.js configuration file that is to be used.
204 | #c.NotebookApp.mathjax_config = 'TeX-AMS-MML_HTMLorMML-full,Safe'
205 |
206 | ## A custom url for MathJax.js. Should be in the form of a case-sensitive url to
207 | # MathJax, for example: /static/components/MathJax/MathJax.js
208 | #c.NotebookApp.mathjax_url = ''
209 |
210 | ## Dict of Python modules to load as notebook server extensions.Entry values can
211 | # be used to enable and disable the loading ofthe extensions. The extensions
212 | # will be loaded in alphabetical order.
213 | #c.NotebookApp.nbserver_extensions = {}
214 |
215 | ## The directory to use for notebooks and kernels.
216 | #c.NotebookApp.notebook_dir = ''
217 | c.NotebookApp.notebook_dir = '/root/notebook'
218 |
219 | ## Whether to open in a browser after starting. The specific browser used is
220 | # platform dependent and determined by the python standard library `webbrowser`
221 | # module, unless it is overridden using the --browser (NotebookApp.browser)
222 | # configuration option.
223 | #c.NotebookApp.open_browser = True
224 | c.NotebookApp.open_browser = False
225 |
226 | ## Hashed password to use for web authentication.
227 | #
228 | # To generate, type in a python/IPython shell:
229 | #
230 | # from notebook.auth import passwd; passwd()
231 | #
232 | # The string should be of the form type:salt:hashed-password.
233 | c.NotebookApp.password = 'sha1:c1ff390e0b6c:5298138a410f2077b46bf45d61536add40ee5e13'
234 |
235 | ## Forces users to use a password for the Notebook server. This is useful in a
236 | # multi user environment, for instance when everybody in the LAN can access each
237 | # other's machine through ssh.
238 | #
239 | # In such a case, server the notebook server on localhost is not secure since
240 | # any user can connect to the notebook server via ssh.
241 | #c.NotebookApp.password_required = False
242 |
243 | ## The port the notebook server will listen on.
244 | c.NotebookApp.port = 8080
245 |
246 | ## The number of additional ports to try if the specified port is not available.
247 | #c.NotebookApp.port_retries = 50
248 |
249 | ## DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib.
250 | #c.NotebookApp.pylab = 'disabled'
251 |
252 | ## (sec) Time window used to check the message and data rate limits.
253 | #c.NotebookApp.rate_limit_window = 3
254 |
255 | ## Reraise exceptions encountered loading server extensions?
256 | #c.NotebookApp.reraise_server_extension_failures = False
257 |
258 | ## DEPRECATED use the nbserver_extensions dict instead
259 | #c.NotebookApp.server_extensions = []
260 |
261 | ## The session manager class to use.
262 | #c.NotebookApp.session_manager_class = 'notebook.services.sessions.sessionmanager.SessionManager'
263 |
264 | ## Shut down the server after N seconds with no kernels or terminals running and
265 | # no activity. This can be used together with culling idle kernels
266 | # (MappingKernelManager.cull_idle_timeout) to shutdown the notebook server when
267 | # it's not in use. This is not precisely timed: it may shut down up to a minute
268 | # later. 0 (the default) disables this automatic shutdown.
269 | #c.NotebookApp.shutdown_no_activity_timeout = 0
270 |
271 | ## Supply SSL options for the tornado HTTPServer. See the tornado docs for
272 | # details.
273 | #c.NotebookApp.ssl_options = {}
274 |
275 | ## Supply overrides for terminado. Currently only supports "shell_command".
276 | #c.NotebookApp.terminado_settings = {}
277 |
278 | ## Token used for authenticating first-time connections to the server.
279 | #
280 | # When no password is enabled, the default is to generate a new, random token.
281 | #
282 | # Setting to an empty string disables authentication altogether, which is NOT
283 | # RECOMMENDED.
284 | #c.NotebookApp.token = ''
285 |
286 | ## Supply overrides for the tornado.web.Application that the Jupyter notebook
287 | # uses.
288 | #c.NotebookApp.tornado_settings = {}
289 |
290 | ## Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-
291 | # For headerssent by the upstream reverse proxy. Necessary if the proxy handles
292 | # SSL
293 | #c.NotebookApp.trust_xheaders = False
294 |
295 | ## DEPRECATED, use tornado_settings
296 | #c.NotebookApp.webapp_settings = {}
297 |
298 | ## Specify Where to open the notebook on startup. This is the
299 | # `new` argument passed to the standard library method `webbrowser.open`.
300 | # The behaviour is not guaranteed, but depends on browser support. Valid
301 | # values are:
302 | # 2 opens a new tab,
303 | # 1 opens a new window,
304 | # 0 opens in an existing window.
305 | # See the `webbrowser.open` documentation for details.
306 | #c.NotebookApp.webbrowser_open_new = 2
307 |
308 | ## Set the tornado compression options for websocket connections.
309 | #
310 | # This value will be returned from
311 | # :meth:`WebSocketHandler.get_compression_options`. None (default) will disable
312 | # compression. A dict (even an empty one) will enable compression.
313 | #
314 | # See the tornado docs for WebSocketHandler.get_compression_options for details.
315 | #c.NotebookApp.websocket_compression_options = None
316 |
317 | ## The base URL for websockets, if it differs from the HTTP server (hint: it
318 | # almost certainly doesn't).
319 | #
320 | # Should be in the form of an HTTP origin: ws[s]://hostname[:port]
321 | #c.NotebookApp.websocket_url = ''
322 |
323 | #------------------------------------------------------------------------------
324 | # ConnectionFileMixin(LoggingConfigurable) configuration
325 | #------------------------------------------------------------------------------
326 |
327 | ## Mixin for configurable classes that work with connection files
328 |
329 | ## JSON file in which to store connection info [default: kernel-.json]
330 | #
331 | # This file will contain the IP, ports, and authentication key needed to connect
332 | # clients to this kernel. By default, this file will be created in the security
333 | # dir of the current profile, but can be specified by absolute path.
334 | #c.ConnectionFileMixin.connection_file = ''
335 |
336 | ## set the control (ROUTER) port [default: random]
337 | #c.ConnectionFileMixin.control_port = 0
338 |
339 | ## set the heartbeat port [default: random]
340 | #c.ConnectionFileMixin.hb_port = 0
341 |
342 | ## set the iopub (PUB) port [default: random]
343 | #c.ConnectionFileMixin.iopub_port = 0
344 |
345 | ## Set the kernel's IP address [default localhost]. If the IP address is
346 | # something other than localhost, then Consoles on other machines will be able
347 | # to connect to the Kernel, so be careful!
348 | #c.ConnectionFileMixin.ip = ''
349 |
350 | ## set the shell (ROUTER) port [default: random]
351 | #c.ConnectionFileMixin.shell_port = 0
352 |
353 | ## set the stdin (ROUTER) port [default: random]
354 | #c.ConnectionFileMixin.stdin_port = 0
355 |
356 | ##
357 | #c.ConnectionFileMixin.transport = 'tcp'
358 |
359 | #------------------------------------------------------------------------------
360 | # KernelManager(ConnectionFileMixin) configuration
361 | #------------------------------------------------------------------------------
362 |
363 | ## Manages a single kernel in a subprocess on this host.
364 | #
365 | # This version starts kernels with Popen.
366 |
367 | ## Should we autorestart the kernel if it dies.
368 | #c.KernelManager.autorestart = True
369 |
370 | ## DEPRECATED: Use kernel_name instead.
371 | #
372 | # The Popen Command to launch the kernel. Override this if you have a custom
373 | # kernel. If kernel_cmd is specified in a configuration file, Jupyter does not
374 | # pass any arguments to the kernel, because it cannot make any assumptions about
375 | # the arguments that the kernel understands. In particular, this means that the
376 | # kernel does not receive the option --debug if it given on the Jupyter command
377 | # line.
378 | #c.KernelManager.kernel_cmd = []
379 |
380 | ## Time to wait for a kernel to terminate before killing it, in seconds.
381 | #c.KernelManager.shutdown_wait_time = 5.0
382 |
383 | #------------------------------------------------------------------------------
384 | # Session(Configurable) configuration
385 | #------------------------------------------------------------------------------
386 |
387 | ## Object for handling serialization and sending of messages.
388 | #
389 | # The Session object handles building messages and sending them with ZMQ sockets
390 | # or ZMQStream objects. Objects can communicate with each other over the
391 | # network via Session objects, and only need to work with the dict-based IPython
392 | # message spec. The Session will handle serialization/deserialization, security,
393 | # and metadata.
394 | #
395 | # Sessions support configurable serialization via packer/unpacker traits, and
396 | # signing with HMAC digests via the key/keyfile traits.
397 | #
398 | # Parameters ----------
399 | #
400 | # debug : bool
401 | # whether to trigger extra debugging statements
402 | # packer/unpacker : str : 'json', 'pickle' or import_string
403 | # importstrings for methods to serialize message parts. If just
404 | # 'json' or 'pickle', predefined JSON and pickle packers will be used.
405 | # Otherwise, the entire importstring must be used.
406 | #
407 | # The functions must accept at least valid JSON input, and output *bytes*.
408 | #
409 | # For example, to use msgpack:
410 | # packer = 'msgpack.packb', unpacker='msgpack.unpackb'
411 | # pack/unpack : callables
412 | # You can also set the pack/unpack callables for serialization directly.
413 | # session : bytes
414 | # the ID of this Session object. The default is to generate a new UUID.
415 | # username : unicode
416 | # username added to message headers. The default is to ask the OS.
417 | # key : bytes
418 | # The key used to initialize an HMAC signature. If unset, messages
419 | # will not be signed or checked.
420 | # keyfile : filepath
421 | # The file containing a key. If this is set, `key` will be initialized
422 | # to the contents of the file.
423 |
424 | ## Threshold (in bytes) beyond which an object's buffer should be extracted to
425 | # avoid pickling.
426 | #c.Session.buffer_threshold = 1024
427 |
428 | ## Whether to check PID to protect against calls after fork.
429 | #
430 | # This check can be disabled if fork-safety is handled elsewhere.
431 | #c.Session.check_pid = True
432 |
433 | ## Threshold (in bytes) beyond which a buffer should be sent without copying.
434 | #c.Session.copy_threshold = 65536
435 |
436 | ## Debug output in the Session
437 | #c.Session.debug = False
438 |
439 | ## The maximum number of digests to remember.
440 | #
441 | # The digest history will be culled when it exceeds this value.
442 | #c.Session.digest_history_size = 65536
443 |
444 | ## The maximum number of items for a container to be introspected for custom
445 | # serialization. Containers larger than this are pickled outright.
446 | #c.Session.item_threshold = 64
447 |
448 | ## execution key, for signing messages.
449 | #c.Session.key = b''
450 |
451 | ## path to file containing execution key.
452 | #c.Session.keyfile = ''
453 |
454 | ## Metadata dictionary, which serves as the default top-level metadata dict for
455 | # each message.
456 | #c.Session.metadata = {}
457 |
458 | ## The name of the packer for serializing messages. Should be one of 'json',
459 | # 'pickle', or an import name for a custom callable serializer.
460 | #c.Session.packer = 'json'
461 |
462 | ## The UUID identifying this session.
463 | #c.Session.session = ''
464 |
465 | ## The digest scheme used to construct the message signatures. Must have the form
466 | # 'hmac-HASH'.
467 | #c.Session.signature_scheme = 'hmac-sha256'
468 |
469 | ## The name of the unpacker for unserializing messages. Only used with custom
470 | # functions for `packer`.
471 | #c.Session.unpacker = 'json'
472 |
473 | ## Username for the Session. Default is your system username.
474 | #c.Session.username = 'username'
475 |
476 | #------------------------------------------------------------------------------
477 | # MultiKernelManager(LoggingConfigurable) configuration
478 | #------------------------------------------------------------------------------
479 |
480 | ## A class for managing multiple kernels.
481 |
482 | ## The name of the default kernel to start
483 | #c.MultiKernelManager.default_kernel_name = 'python3'
484 |
485 | ## The kernel manager class. This is configurable to allow subclassing of the
486 | # KernelManager for customized behavior.
487 | #c.MultiKernelManager.kernel_manager_class = 'jupyter_client.ioloop.IOLoopKernelManager'
488 |
489 | #------------------------------------------------------------------------------
490 | # MappingKernelManager(MultiKernelManager) configuration
491 | #------------------------------------------------------------------------------
492 |
493 | ## A KernelManager that handles notebook mapping and HTTP error handling
494 |
495 | ## Whether messages from kernels whose frontends have disconnected should be
496 | # buffered in-memory.
497 | #
498 | # When True (default), messages are buffered and replayed on reconnect, avoiding
499 | # lost messages due to interrupted connectivity.
500 | #
501 | # Disable if long-running kernels will produce too much output while no
502 | # frontends are connected.
503 | #c.MappingKernelManager.buffer_offline_messages = True
504 |
505 | ## Whether to consider culling kernels which are busy. Only effective if
506 | # cull_idle_timeout > 0.
507 | #c.MappingKernelManager.cull_busy = False
508 |
509 | ## Whether to consider culling kernels which have one or more connections. Only
510 | # effective if cull_idle_timeout > 0.
511 | #c.MappingKernelManager.cull_connected = False
512 |
513 | ## Timeout (in seconds) after which a kernel is considered idle and ready to be
514 | # culled. Values of 0 or lower disable culling. Very short timeouts may result
515 | # in kernels being culled for users with poor network connections.
516 | #c.MappingKernelManager.cull_idle_timeout = 0
517 |
518 | ## The interval (in seconds) on which to check for idle kernels exceeding the
519 | # cull timeout value.
520 | #c.MappingKernelManager.cull_interval = 300
521 |
522 | ##
523 | #c.MappingKernelManager.root_dir = ''
524 |
525 | #------------------------------------------------------------------------------
526 | # ContentsManager(LoggingConfigurable) configuration
527 | #------------------------------------------------------------------------------
528 |
529 | ## Base class for serving files and directories.
530 | #
531 | # This serves any text or binary file, as well as directories, with special
532 | # handling for JSON notebook documents.
533 | #
534 | # Most APIs take a path argument, which is always an API-style unicode path, and
535 | # always refers to a directory.
536 | #
537 | # - unicode, not url-escaped
538 | # - '/'-separated
539 | # - leading and trailing '/' will be stripped
540 | # - if unspecified, path defaults to '',
541 | # indicating the root path.
542 |
543 | ## Allow access to hidden files
544 | #c.ContentsManager.allow_hidden = False
545 |
546 | ##
547 | #c.ContentsManager.checkpoints = None
548 |
549 | ##
550 | #c.ContentsManager.checkpoints_class = 'notebook.services.contents.checkpoints.Checkpoints'
551 |
552 | ##
553 | #c.ContentsManager.checkpoints_kwargs = {}
554 |
555 | ## handler class to use when serving raw file requests.
556 | #
557 | # Default is a fallback that talks to the ContentsManager API, which may be
558 | # inefficient, especially for large files.
559 | #
560 | # Local files-based ContentsManagers can use a StaticFileHandler subclass, which
561 | # will be much more efficient.
562 | #
563 | # Access to these files should be Authenticated.
564 | #c.ContentsManager.files_handler_class = 'notebook.files.handlers.FilesHandler'
565 |
566 | ## Extra parameters to pass to files_handler_class.
567 | #
568 | # For example, StaticFileHandlers generally expect a `path` argument specifying
569 | # the root directory from which to serve files.
570 | #c.ContentsManager.files_handler_params = {}
571 |
572 | ## Glob patterns to hide in file and directory listings.
573 | #c.ContentsManager.hide_globs = ['__pycache__', '*.pyc', '*.pyo', '.DS_Store', '*.so', '*.dylib', '*~']
574 |
575 | ## Python callable or importstring thereof
576 | #
577 | # To be called on a contents model prior to save.
578 | #
579 | # This can be used to process the structure, such as removing notebook outputs
580 | # or other side effects that should not be saved.
581 | #
582 | # It will be called as (all arguments passed by keyword)::
583 | #
584 | # hook(path=path, model=model, contents_manager=self)
585 | #
586 | # - model: the model to be saved. Includes file contents.
587 | # Modifying this dict will affect the file that is stored.
588 | # - path: the API path of the save destination
589 | # - contents_manager: this ContentsManager instance
590 | #c.ContentsManager.pre_save_hook = None
591 |
592 | ##
593 | #c.ContentsManager.root_dir = '/'
594 |
595 | ## The base name used when creating untitled directories.
596 | #c.ContentsManager.untitled_directory = 'Untitled Folder'
597 |
598 | ## The base name used when creating untitled files.
599 | #c.ContentsManager.untitled_file = 'untitled'
600 |
601 | ## The base name used when creating untitled notebooks.
602 | #c.ContentsManager.untitled_notebook = 'Untitled'
603 |
604 | #------------------------------------------------------------------------------
605 | # FileManagerMixin(Configurable) configuration
606 | #------------------------------------------------------------------------------
607 |
608 | ## Mixin for ContentsAPI classes that interact with the filesystem.
609 | #
610 | # Provides facilities for reading, writing, and copying both notebooks and
611 | # generic files.
612 | #
613 | # Shared by FileContentsManager and FileCheckpoints.
614 | #
615 | # Note ---- Classes using this mixin must provide the following attributes:
616 | #
617 | # root_dir : unicode
618 | # A directory against against which API-style paths are to be resolved.
619 | #
620 | # log : logging.Logger
621 |
622 | ## By default notebooks are saved on disk on a temporary file and then if
623 | # succefully written, it replaces the old ones. This procedure, namely
624 | # 'atomic_writing', causes some bugs on file system whitout operation order
625 | # enforcement (like some networked fs). If set to False, the new notebook is
626 | # written directly on the old one which could fail (eg: full filesystem or quota
627 | # )
628 | #c.FileManagerMixin.use_atomic_writing = True
629 |
630 | #------------------------------------------------------------------------------
631 | # FileContentsManager(FileManagerMixin,ContentsManager) configuration
632 | #------------------------------------------------------------------------------
633 |
634 | ## If True (default), deleting files will send them to the platform's
635 | # trash/recycle bin, where they can be recovered. If False, deleting files
636 | # really deletes them.
637 | #c.FileContentsManager.delete_to_trash = True
638 |
639 | ## Python callable or importstring thereof
640 | #
641 | # to be called on the path of a file just saved.
642 | #
643 | # This can be used to process the file on disk, such as converting the notebook
644 | # to a script or HTML via nbconvert.
645 | #
646 | # It will be called as (all arguments passed by keyword)::
647 | #
648 | # hook(os_path=os_path, model=model, contents_manager=instance)
649 | #
650 | # - path: the filesystem path to the file just written - model: the model
651 | # representing the file - contents_manager: this ContentsManager instance
652 | #c.FileContentsManager.post_save_hook = None
653 |
654 | ##
655 | #c.FileContentsManager.root_dir = ''
656 |
657 | ## DEPRECATED, use post_save_hook. Will be removed in Notebook 5.0
658 | #c.FileContentsManager.save_script = False
659 |
660 | #------------------------------------------------------------------------------
661 | # NotebookNotary(LoggingConfigurable) configuration
662 | #------------------------------------------------------------------------------
663 |
664 | ## A class for computing and verifying notebook signatures.
665 |
666 | ## The hashing algorithm used to sign notebooks.
667 | #c.NotebookNotary.algorithm = 'sha256'
668 |
669 | ## The sqlite file in which to store notebook signatures. By default, this will
670 | # be in your Jupyter data directory. You can set it to ':memory:' to disable
671 | # sqlite writing to the filesystem.
672 | #c.NotebookNotary.db_file = ''
673 |
674 | ## The secret key with which notebooks are signed.
675 | #c.NotebookNotary.secret = b''
676 |
677 | ## The file where the secret key is stored.
678 | #c.NotebookNotary.secret_file = ''
679 |
680 | ## A callable returning the storage backend for notebook signatures. The default
681 | # uses an SQLite database.
682 | #c.NotebookNotary.store_factory = traitlets.Undefined
683 |
684 | #------------------------------------------------------------------------------
685 | # KernelSpecManager(LoggingConfigurable) configuration
686 | #------------------------------------------------------------------------------
687 |
688 | ## If there is no Python kernelspec registered and the IPython kernel is
689 | # available, ensure it is added to the spec list.
690 | #c.KernelSpecManager.ensure_native_kernel = True
691 |
692 | ## The kernel spec class. This is configurable to allow subclassing of the
693 | # KernelSpecManager for customized behavior.
694 | #c.KernelSpecManager.kernel_spec_class = 'jupyter_client.kernelspec.KernelSpec'
695 |
696 | ## Whitelist of allowed kernel names.
697 | #
698 | # By default, all installed kernels are allowed.
699 | #c.KernelSpecManager.whitelist = set()
700 |
--------------------------------------------------------------------------------