AWSとCloudflareによるプレビュー環境
43207 ワード
オンデマンドプレビュー環境は、オンザフライで一時的なインフラストラクチャと孤立した環境を回転させる戦略です.これは、リリースプロセスの初期段階で製品やQAなどの他のチームとのディスカッションを開き、クロスチームの可視性を向上させます.したがって、この記事では、我々はどのように我々はこれを達成することができます参照してくださいよAWS ECS and Cloudflare .
すべてのコードが利用可能ですrepository
なぜ我々はそれが必要ですか?
これがどのように我々のリリースとチームワークフロープロセスに利益をもたらすかについて見ましょう.これは私の個人的経験からの例です.
通常のワークフロー
現時点では、QAと製品のレビューは密接にリリースに結合され、それが頻繁に変更をロールバックするときには、それ自体はリリース自体にロールバックするのは難しい.
新しいワークフロー
彼らは変更についてのソフトレビューを行うことができるように、これはQAと製品チームに大きな利益を提供します.変更するまでステージング環境に到達するまで製品チームはもはや待機する必要があります.QAチームと同じように、プルリクエストレベルで変更をテストできます.
挑戦
私が直面しているいくつかの課題を見てみましょう.
SSL
大きな課題の一つはSSLを設定していたからですcannot 証明書をAWS ACM 独自のカスタムNginx ACMとしてのプロキシは、クラウドフロント、ALB、APIゲートウェイなどのAWSサービスだけで動作します.
これを研究しながらオンラインで見たアプローチはいくつかあります. つのアプローチはLet's Encrypt 一時的なSSL certsを生成します.はい、どうぞgood implementation for this . しかし、これは我々が生成するすべてのCERTSを管理する他の問題を提示します. もう一つのアプローチは、ちょうど新しいルート53記録を加えて、それからALBにそれを進めることです.問題は、これらのリソースを提供する必要はありませんが、我々は提供する必要がありますし、それらをかなり破壊する! 曇りArgo Tunnel 救助に!これによって、我々は単にすべての入口を閉めることができて、代わりにトンネルを通して我々の交通を公開することができます.その後、プロキシのDNSレコードを作成することができますCloudFlareは私たちのためにSSLのスタッフを扱うことができます!
ここで私はどこで詳細アルゴトンネルカバー
セキュリティ
この重要な部分はセキュリティです.私のAWSインフラストラクチャへのバックドアを、意図的に、あるいはミスによって、インターネットに対して単に私のプル要求における危険な変化を含んでいるだけでいるのを止めているのです.我々は、これらの一時的な環境を暴露する安全な方法を必要とします.
最初に解決した解決策はAWS VPN または同様の何か.それで、我々は我々のVPNを使っている人々に環境へのアクセスを許すだけです.良い音?しかし、結局、これは我々がVPNをセットアップして、使用するためにあらゆるチームメンバーに乗り込むことを我々に要求しました.
曇りAccess ゲームチェンジャーは、それは最大50ユーザーに無料です!これは私がVPNのない一時的な環境への安全で、より速い、そして、ゼロ信頼アクセスを作成するために必要としたものです.
私たちはアクセスセクションで詳細にすべてのCloudFlare使用について話します.
建築
我々のアーキテクチャはかなりシンプルで直感的です.左側では、我々はどのように我々のアプリを構築し、開発者が新しいプルの要求を開き、ラベルを我々のインフラストラクチャを提供する方法を見ることができます.興味深いコンポーネントは、我々が実装するカスタムスクリプトです.途中で、我々は我々の基盤セットアップについていくつかの詳細に入ります.右側では、私たちは、どのように我々の一時的な環境終点へのアクセスを確保するために、Cloudflare ArgoトンネルとCloudFlareアクセスを利用するかについて見ます.
これを見るhigher resolution
実装
全体を三つのセクションに分けました. セットアップ インフラ アクセス 注意: grepリポジトリ
セットアップ
この手順では、Githubのアクションとカスタムプロビジョニングスクリプトの使用方法を確認します.
ギタブアクション
私たちは基本的に
供給
一旦プル要求があるならば、我々は我々のプレビュー環境をつくります CloudFlare Argoトンネル、アクセスポリシー、およびアクセスアプリケーションを作成します. 資格情報を保存する
ビルド中に私たちのDockerイメージに資格情報をコピーするので、我々は実行時にCloudFlareにアウトバウンド接続を作成することができます. 塗りつぶし、タスク定義を登録します. Githubからのイベントを処理するスクリプトと一時的なAWSとCloudFlareインフラストラクチャ.
破壊する
一旦プル要求があるならば、我々は我々のプレビュー環境を破壊します 一時的なAWSとCloudFlareリソースを破壊する GitHubアクションは既にリポジトリに含まれています
このスクリプトは、我々の一時的なインフラを提供するか破壊するのを助けます
インフラ
我々が我々の一時的な仕事を走らせる前に、我々が必要とする基盤は、ここにあります.私は完全な実装をチェックするためにここにスニペットを追加しました
注:お馴染みのない場合は、地形についての詳細を学ぶことができます
アクセス
我々のアプリケーションとインフラストラクチャを実行しているので、アクセスについて話しましょう.より具体的にどのように活用することができますCloudflare Access .
私たちが以前に議論したように、トンネルを作った後に、私たちはproxied
アクセスポリシー
それから、我々はAccess Policy 誰が我々の安全な終点にアクセスできるかについて制御するために.我々も、MFAを実施することができます!
アクセスグループ
これは、より良い曲のものですが、アクセスグループを使用するなどのチームを作成することができます
用途
以下に、プレビュー環境の使い方を説明します.
供給 開発者はプル要求を作成します.
開発者のラベルは、
GitHubアクションが完了すると、以下のようなプル要求に関するコメントを残します.環境は
製品またはQAチームはプル要求を評価するために新しい環境を使用します.Cloudflareへのアクセスをする誰でも.
破壊する 破壊するには、いずれかのプル要求を閉じることができますまたは私たちの破壊ステップを開始するには、ラベルを解除します.
改善
改善のために、1つのアイデアは移動するスクリプトを移動して、それをterraformプロバイダーにすることができます.
費用推定
コストはかなりに翻訳されますAWS ECS pricing ( fargateで) Cloudflareのフリー層を使用しているので.
結論
私はこの記事は、常に任意の問題に直面している場合に役立つように役立つと思った.
うまくいけば、これはあなたの組織でリリースプロセスの初期段階でQA、ソリューションチームとのいくつかのコラボレーションをもたらすでしょう.
すべてのコードが利用可能ですrepository
なぜ我々はそれが必要ですか?
これがどのように我々のリリースとチームワークフロープロセスに利益をもたらすかについて見ましょう.これは私の個人的経験からの例です.
通常のワークフロー
現時点では、QAと製品のレビューは密接にリリースに結合され、それが頻繁に変更をロールバックするときには、それ自体はリリース自体にロールバックするのは難しい.
新しいワークフロー
彼らは変更についてのソフトレビューを行うことができるように、これはQAと製品チームに大きな利益を提供します.変更するまでステージング環境に到達するまで製品チームはもはや待機する必要があります.QAチームと同じように、プルリクエストレベルで変更をテストできます.
挑戦
私が直面しているいくつかの課題を見てみましょう.
SSL
大きな課題の一つはSSLを設定していたからですcannot 証明書をAWS ACM 独自のカスタムNginx ACMとしてのプロキシは、クラウドフロント、ALB、APIゲートウェイなどのAWSサービスだけで動作します.
これを研究しながらオンラインで見たアプローチはいくつかあります.
ここで私はどこで詳細アルゴトンネルカバー
セキュリティ
この重要な部分はセキュリティです.私のAWSインフラストラクチャへのバックドアを、意図的に、あるいはミスによって、インターネットに対して単に私のプル要求における危険な変化を含んでいるだけでいるのを止めているのです.我々は、これらの一時的な環境を暴露する安全な方法を必要とします.
最初に解決した解決策はAWS VPN または同様の何か.それで、我々は我々のVPNを使っている人々に環境へのアクセスを許すだけです.良い音?しかし、結局、これは我々がVPNをセットアップして、使用するためにあらゆるチームメンバーに乗り込むことを我々に要求しました.
曇りAccess ゲームチェンジャーは、それは最大50ユーザーに無料です!これは私がVPNのない一時的な環境への安全で、より速い、そして、ゼロ信頼アクセスを作成するために必要としたものです.
私たちはアクセスセクションで詳細にすべてのCloudFlare使用について話します.
建築
我々のアーキテクチャはかなりシンプルで直感的です.左側では、我々はどのように我々のアプリを構築し、開発者が新しいプルの要求を開き、ラベルを我々のインフラストラクチャを提供する方法を見ることができます.興味深いコンポーネントは、我々が実装するカスタムスクリプトです.途中で、我々は我々の基盤セットアップについていくつかの詳細に入ります.右側では、私たちは、どのように我々の一時的な環境終点へのアクセスを確保するために、Cloudflare ArgoトンネルとCloudFlareアクセスを利用するかについて見ます.
これを見るhigher resolution
実装
全体を三つのセクションに分けました.
todo-
提供するために必要なすべてのものを得るには(すなわち、keys , token )セットアップ
この手順では、Githubのアクションとカスタムプロビジョニングスクリプトの使用方法を確認します.
ギタブアクション
私たちは基本的に
pull_request
次の種類のイベントlabeled
, unlabeled
, synchronize
, closed
. 以下の手順を行います.供給
一旦プル要求があるならば、我々は我々のプレビュー環境をつくります
labeled
, and synchronize
一度新しいコミットがプッシュされます.config.yml
破壊する
一旦プル要求があるならば、我々は我々のプレビュー環境を破壊します
closed
, or unlabeled
..github/workflows/preview-environment.yml
. これがスニペットです.name: Preview Environment
on:
pull_request:
types: [labeled, unlabeled, synchronize, closed]
branches:
- develop
env: ...
jobs:
provision:
name: Provision
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'preview' && github.event.pull_request.state == 'open' || github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'preview') }}
steps: ...
destroy:
name: Destroy
if: ${{ github.event.action == 'unlabeled' && github.event.label.name == 'preview' || github.event.action == 'closed' }}
steps: ...
プロビジョニングスクリプトこのスクリプトは、我々の一時的なインフラを提供するか破壊するのを助けます
scripts/preview
. プロビジョニングされたインフラストラクチャについて維持する方法はありませんので、ブランチ名を単にプロセス名を通してスラッグや一意のIDとして使用します.このスクリプトはconfig.ts
下記の通り.import * as env from 'env-var';
const config = {
// Domain for Cloudflare access policy
domain: '<todo_your_domain>',
aws: {
region: 'us-east-1',
},
github: {
// Token and Pull request no. will be available in Github Action
token: env.get('GITHUB_TOKEN').required().asString(),
pull_number: env.get('PULL_NUMBER').required().asInt(),
},
vpc: {
securityGroups: {
filter: '<todo_your_security_group_tag>',
},
subnets: {
filter: '<todo_your_subnet_tag>',
},
},
ecs: {
cluster: '<todo_your_ecs_cluster_name>',
},
cloudflare: {
path: './outputs/tunnel',
auth_email: '<todo_your_cloudflare_email>',
api_key: env.get('CLOUDFLARE_API_KEY').required().asString(),
token: env.get('CLOUDFLARE_API_TOKEN').required().asString(),
accountId: env.get('CLOUDFLARE_ACCOUNT_ID').required().asString(),
zoneId: env.get('CLOUDFLARE_ZONE_ID').required().asString(),
domain: '<todo_your_cloudflare_domain>',
},
};
export default config;
それはすべて一緒に来るpreview.ts
:import * as github from '@actions/github';
import slugify from 'slugify';
import CloudflareUtils from './utils/cloudflare';
import ECSUtils from './utils/ecs';
import * as GithubUtils from './utils/github';
import * as VPCUtils from './utils/vpc';
import log from './utils/log';
interface PreviewInterface {
provision(taskDefArn: string): Promise<void>;
destroy(): Promise<void>;
tunnel(): Promise<void>;
}
class Preview implements PreviewInterface {
private slug: string;
constructor(branch: string) {
const options = {
lower: true,
};
const suffix = `${branch}-preview`;
this.slug = slugify(suffix, options);
log.info(`Using slug "${this.slug}" for branch "${branch}"`);
}
async provision(taskDefArn: string): Promise<void> {
try {
log.info(`Provisioning resources for task definition arn: ${taskDefArn}`);
const subnets = await VPCUtils.getSubnets();
const securityGroups = await VPCUtils.getSecurityGroups();
const ecs = new ECSUtils(this.slug);
const cloudflare = new CloudflareUtils(this.slug);
await ecs.runTask(taskDefArn, subnets, securityGroups);
const comment = `Your preview environment should be up at https://${cloudflare.domain} in few moments! 🎉`;
if (github.context.payload.action === 'labeled') {
await GithubUtils.commentOnPR(comment);
}
log.success(comment);
} catch (error) {
log.error(error);
log.warn('Performing rollback!');
this.destroy();
process.exit(1);
}
}
async destroy(): Promise<void> {
try {
log.info(`Destroying resources`);
const ecs = new ECSUtils(this.slug);
const cloudflare = new CloudflareUtils(this.slug);
await ecs.stopTask();
await cloudflare.removeDNSRecord();
await cloudflare.deleteTunnels();
await cloudflare.removeAccess();
log.success('Resources destroyed');
} catch (error) {
log.error(error);
process.exit(1);
}
}
async tunnel(): Promise<void> {
try {
const cloudflare = new CloudflareUtils(this.slug);
const tunnelId = await cloudflare.createTunnel();
cloudflare.createConfigFile(tunnelId);
await cloudflare.addDNSRecord(tunnelId);
await cloudflare.createAccess();
log.success('Tunnel setup complete');
} catch (error) {
log.error(error);
process.exit(1);
}
}
}
export default Preview;
次のように使用します.preview/commands/tunnel.ts
import Preview from '../preview';
import * as GithubUtils from '../utils/github';
async function run(): Promise<void> {
const branch = await GithubUtils.getCurrentBranch();
const preview = new Preview(branch);
await preview.tunnel();
}
run();
使用法:$ yarn tunnel
これはCloudFlareconfig.yml
下記のように.tunnel: <tunnel-id>
credentials-file: /root/.cloudflared/<tunnel-id>.json
ingress:
- hostname: subdomain.domain.com
service: http://localhost:4000
- service: http_status:404
preview/commands/provision.ts
:import Preview from '../preview';
import { ArgumentParser } from 'argparse';
import * as GithubUtils from '../utils/github';
const parser = new ArgumentParser({
description: 'Provision preview environment',
});
parser.add_argument('-td', '--task-def-arn', {
required: true,
help: 'Task definition arn',
});
async function run(): Promise<void> {
const { task_def_arn } = parser.parse_args();
const branch = await GithubUtils.getCurrentBranch();
const preview = new Preview(branch);
await preview.provision(task_def_arn);
}
run();
使用法:$ yarn provision --task-def-arn $TASK_DEFINITION
preview/commands/destroy.ts
:import Preview from '../preview';
import * as GithubUtils from '../utils/github';
async function run(): Promise<void> {
const branch = await GithubUtils.getCurrentBranch();
const preview = new Preview(branch);
await preview.destroy();
}
run();
使用法:$ yarn destroy
インフラ
我々が我々の一時的な仕事を走らせる前に、我々が必要とする基盤は、ここにあります.私は完全な実装をチェックするためにここにスニペットを追加しました
infrastructure
倉庫のフォルダ.使っているterraform 供給するには注:お馴染みのない場合は、地形についての詳細を学ぶことができます
# ECR repository
resource "aws_ecr_repository" "ecr_repository" {
name = "app-repository"
image_tag_mutability = "IMMUTABLE"
image_scanning_configuration {
scan_on_push = true
}
}
# ECS task definition used by ECS service
resource "aws_ecs_task_definition" "task_definition" {
family = "app-task-definition"
network_mode = "awsvpc"
cpu = 4096
memory = 8192
requires_compatibilities = ["FARGATE"]
container_definitions = jsonencode([
{
"name": "app",
"image": "nginx:latest",
"essential": true,
"portMappings": [
{
"containerPort": 4000,
"hostPort": 4000
}
]
}
])
task_role_arn = aws_iam_role.task_execution_role.arn
execution_role_arn = aws_iam_role.task_execution_role.arn
}
# Security group
resource "aws_security_group" "security_group" {
name = "app-security-group"
vpc_id = var.vpc_id
ingress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# ECS cluster
resource "aws_ecs_cluster" "cluster" {
name = "ecs-cluster"
capacity_providers = ["FARGATE"]
}
resource "aws_cloudwatch_log_group" "log_group" {
name = "/ecs/app-log-group"
}
アクセス
我々のアプリケーションとインフラストラクチャを実行しているので、アクセスについて話しましょう.より具体的にどのように活用することができますCloudflare Access .
私たちが以前に議論したように、トンネルを作った後に、私たちはproxied
CNAME
DNSレコードCloudflare SDK 下記のように.アクセスポリシー
それから、我々はAccess Policy 誰が我々の安全な終点にアクセスできるかについて制御するために.我々も、MFAを実施することができます!
アクセスグループ
これは、より良い曲のものですが、アクセスグループを使用するなどのチームを作成することができます
Engineering
, Product
, QA
など、我々のアクセスポリシーを設定しながら、これらのグループを使用してはるかに.これをあなたに任せます.用途
以下に、プレビュー環境の使い方を説明します.
供給
preview
レーベル.ラベル付けされると、我々のGithubアクションは、アプリケーションを構築し、インフラストラクチャを提供する必要があります.https://branch-slug.your-domain.com
.person@your_domain.com
), IDプロバイダでログインできますOkta ) プレビュー環境にアクセスします.破壊する
改善
改善のために、1つのアイデアは移動するスクリプトを移動して、それをterraformプロバイダーにすることができます.
費用推定
コストはかなりに翻訳されますAWS ECS pricing ( fargateで) Cloudflareのフリー層を使用しているので.
結論
私はこの記事は、常に任意の問題に直面している場合に役立つように役立つと思った.
うまくいけば、これはあなたの組織でリリースプロセスの初期段階でQA、ソリューションチームとのいくつかのコラボレーションをもたらすでしょう.
Reference
この問題について(AWSとCloudflareによるプレビュー環境), 我々は、より多くの情報をここで見つけました https://dev.to/karanpratapsingh/preview-environments-with-aws-ecs-cloudflare-3hdhテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol