20190705_CloudNativeKansai__4.pdf

 20190705_CloudNativeKansai__4.pdf

2e2c49f6f3fa33b8f5aad5841774c211?s=128

nezumisannn

July 05, 2019
Tweet

Transcript

  1. Packer/Ansible/Terraformを使った AWS Fargateへのデプロイ Cloud Native Kansai #4 株式会社ビヨンド 寺岡 佑樹

  2. はじめに ・本資料は後日公開します ・資料中に記載されているコードGitHubに公開しています  https://github.com/nezumisannn/aws-fargate-pipeline-example ・資料公開したらTwitterでハッシュタグ付きでつぶやきます

  3. Agenda ・自己紹介 ・利用するツール/サービスの紹介 ・このスライドで作れる環境の構成図 ・環境の作り方 ・まとめ

  4. 自己紹介 resource “my_profile” “nezumisannn” { name = “Yuki.Teraoka” nickname =

    “ねずみさん家。” company = “beyond” job = “Site Reliability Engineer” twitter = “@yktr_sre” skills = [“terraform”,”packer”] }
  5. 利用するツール

  6. 利用するツール Terraform Packer Ansible

  7. 利用するサービス

  8. 利用するサービス Elastic Container Registry Fargate Code Build Code Deploy Code

    Pipeline
  9. 構成図

  10. 構成図 Pipeline git push im age build deploy source

  11. 出来ること ・fargateへのデプロイの自動化(CI/CD) ・GitへのPushをトリガーに、Pull ⇒ Build ⇒ Deployまで処理できる

  12. デモ

  13. 今回のゴール ・CodePipelineの一連の処理を実行できる ・実行した結果、ブラウザの画面に「hello world」と表示されるようにする

  14. 実装

  15. コンテナのビルド Pipeline git push im age build deploy source

  16. コンテナのビルド ・CodeBuildを利用 ・プロジェクトはTerraformで作成 ・ソースプロバイダにGitHubを設定 ・buildspec.ymlにビルド時の処理を記述 ・CodeBuildのビルド用コンテナにPacker/Ansibleをインストール ・Packerのbuildersにdockerを指定 ・provisionersでAnsibleを実行してpost-processorsでECRにpush

  17. resource "aws_codebuild_project" "codebuild" { name = "example" service_role = "${aws_iam_role.role-codebuild.arn}"

    source { type = "GITHUB" location = "https://github.com/nezumisannn/aws-pipeline-example.git" git_clone_depth = 1 } environment { compute_type = "BUILD_GENERAL1_SMALL" image = "aws/codebuild/standard:1.0-1.8.0" image_pull_credentials_type = "CODEBUILD" privileged_mode = true type = "LINUX_CONTAINER" } artifacts { type = "NO_ARTIFACTS" } }
  18. --- version: 0.2 phases: pre_build: commands: - curl -qL -o

    packer.zip https://releases.hashicorp.com/packer/0.12.3/packer_0.12.3_linux_amd64.zip && unzip packer.zip - curl -qL -o jq https://stedolan.github.io/jq/download/linux64/jq && chmod +x ./jq - apt-get install software-properties-common -y - apt-add-repository ppa:ansible/ansible -y - apt-get install ansible -y - apt-get install openssh-client -y - apt-get update - ansible --version - ./packer validate ./packer-build/build.json
  19. build: commands: - echo "Setting AWS credentials" - curl -qL

    -o aws_credentials.json http://169.254.170.2/$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI > aws_credentials.json - aws configure set region ap-northeast-1 - aws configure set aws_access_key_id `./jq -r '.AccessKeyId' aws_credentials.json` - aws configure set aws_secret_access_key `./jq -r '.SecretAccessKey' aws_credentials.json` - aws configure set aws_session_token `./jq -r '.Token' aws_credentials.json` - echo "Build Packer" - ./packer build -debug ./packer-build/build.json - printf '{"Version":"1.0","ImageURI":"%s"}' XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/example-repo:latest > imageDetail.json artifacts: files: imageDetail.json
  20. { "variables": { "ecr_registry_url": "XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com", "ecr_repository": "XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/example-repo" }, "builders": [

    { "type": "docker", "image": "alpine:latest", "commit": true, "run_command": [ "-d", "-t", "-i", "{{.Image}}", "/bin/sh" ], "changes": [ "VOLUME /data", "WORKDIR /data", "EXPOSE 80 443", "ENTRYPOINT [\"docker-entrypoint.sh\"]" ] } ],
  21. "provisioners": [ { "type": "ansible", "user": "root", "playbook_file": "./ansible/operation.yml" }

    ], "post-processors": [ [ { "type": "docker-tag", "repository": "{{user `ecr_repository`}}", "tag": "latest" }, { "type": "docker-push", "ecr_login": true, "login_server": "{{user `ecr_registry_url`}}" } ] ] }
  22. - name: Starting building... hosts: all tasks: - name: Installing

    nginx package: name: nginx state: present - name: Putting nginx config file copy: src: config/nginx/default.conf dest: /etc/nginx/conf.d/default.conf mode: 0755 owner: root group: root - name: Putting index.html copy: src: ../application/index.html dest: /usr/share/nginx/html/index.html mode: 0755 owner: root group: root
  23. - name: Putting entrypoints copy: src: config/{{ item }} dest:

    /usr/local/bin/{{ item }} mode: 0755 owner: root group: root with_items: - docker-entrypoint.sh #!/bin/sh exec nginx -g 'pid /tmp/nginx.pid; daemon off;'
  24. Fargateへのデプロイ Pipeline git push im age build deploy source

  25. Fargateへのデプロイ ・CodeDeployを利用 ・Fargateとデプロイに必要なALB/ターゲットグループはTerraformで作成 ・ローリングアップデートではなくBlue/Greenデプロイを行う

  26. Blue/Greenデプロイ Target 1 Target 2

  27. resource "aws_alb" "alb" { name = "example" security_groups = ["${aws_security_group.alb-sg.id}"]

    subnets = "${var.subnets}" }
  28. ## Target Group resource "aws_alb_target_group" "target_group1" { name = "example-tg1"

    port = 80 protocol = "HTTP" target_type = "ip" vpc_id = "${var.vpc_id}" } resource "aws_alb_target_group" "target_group2" { name = "example-tg2" port = 80 protocol = "HTTP" target_type = "ip" vpc_id = "${var.vpc_id}" }
  29. ## ECS Service resource "aws_ecs_service" "ecs-service" { name = "service-nginx"

    cluster = "${aws_ecs_cluster.ecs-cluster.id}" task_definition = "${aws_ecs_task_definition.ecs-task.arn}" launch_type = "FARGATE" desired_count = 3 health_check_grace_period_seconds = 0 deployment_controller { type = "CODE_DEPLOY" } load_balancer { container_name = "nginx-web" container_port = "80" target_group_arn = "${aws_alb_target_group.target_group1.arn}" } network_configuration { assign_public_ip = true security_groups = [ "${aws_security_group.fargate-sg.id}" ] subnets = "${var.subnets}" } }
  30. ## CodeDeploy APP resource "aws_codedeploy_app" "codedeploy-app" { compute_platform = "ECS"

    name = "AppECS-cluster-example-service-nginx" }
  31. resource "aws_codedeploy_deployment_group" "codedeploy-group" { app_name = "${aws_codedeploy_app.codedeploy-app.name}" service_role_arn = "${aws_iam_role.role-codedeploy.arn}"

    deployment_group_name = "DgpECS-cluster-example-service-nginx" deployment_config_name = "CodeDeployDefault.OneAtATime" ecs_service { cluster_name = "${aws_ecs_cluster.ecs-cluster.name}" service_name = "${aws_ecs_service.ecs-service.name}" } blue_green_deployment_config { deployment_ready_option { action_on_timeout = "CONTINUE_DEPLOYMENT" wait_time_in_minutes = 0 } terminate_blue_instances_on_deployment_success { action = "TERMINATE" termination_wait_time_in_minutes = 0 } }
  32. load_balancer_info { target_group_pair_info { prod_traffic_route { listener_arns = [ "${aws_alb_listener.listener.arn}"

    ] } target_group { name = "${aws_alb_target_group.target_group1.arn}" } target_group { name = "${aws_alb_target_group.target_group2.arn}" } } }
  33. resource "aws_codedeploy_deployment_group" "codedeploy-group" { app_name = "${aws_codedeploy_app.codedeploy-app.name}" service_role_arn = "${aws_iam_role.role-codedeploy.arn}"

    deployment_group_name = "DgpECS-cluster-example-service-nginx" deployment_config_name = "CodeDeployDefault.OneAtATime" ecs_service { cluster_name = "${aws_ecs_cluster.ecs-cluster.name}" service_name = "${aws_ecs_service.ecs-service.name}" } blue_green_deployment_config { deployment_ready_option { action_on_timeout = "CONTINUE_DEPLOYMENT" wait_time_in_minutes = 0 } terminate_blue_instances_on_deployment_success { action = "TERMINATE" termination_wait_time_in_minutes = 0 } }
  34. Pipelineの作成 Pipeline git push im age build deploy source

  35. Pipelineの作成 ・パイプラインのステージをそれぞれ追加する ・ソースステージ:Github ・ビルドステージ:CodeBuild ・デプロイステージ:ECS(ブルー/グリーン) ・git pushをするとPull ⇒ Build ⇒

    Deployが自動実行されるようになる ・パイプラインの設定はTerraformで行う
  36. resource "aws_codepipeline" "codepipeline" { name = "example-pipeline" stage { name

    = "Source" action { category = "Source" configuration = { "Branch" = "master" "Owner" = "XXXXXXXXXX" "PollForSourceChanges" = "false" "Repo" = "XXXXXXXXXX" } name = "Source" output_artifacts = [ "SourceArtifact", ] owner = "ThirdParty" provider = "GitHub" run_order = 1 version = "1" } }
  37. stage { name = "Build" action { category = "Build"

    configuration = { "ProjectName" = "${aws_codebuild_project.codebuild.name}" } input_artifacts = [ "SourceArtifact", ] name = "Build" output_artifacts = [ "BuildArtifact", ] owner = "AWS" provider = "CodeBuild" run_order = 1 version = "1" } }
  38. stage { name = "Deploy" action { category = "Deploy"

    configuration = { "AppSpecTemplateArtifact" = "SourceArtifact" "ApplicationName" = "${aws_codedeploy_app.codedeploy-app.name}" "DeploymentGroupName" = "${aws_codedeploy_deployment_group.codedeploy-group.name}" "Image1ArtifactName" = "BuildArtifact" "Image1ContainerName" = "IMAGE1_NAME" "TaskDefinitionTemplateArtifact" = "SourceArtifact" } input_artifacts = [ "BuildArtifact", "SourceArtifact", ] name = "Deploy" owner = "AWS" provider = "CodeDeployToECS" run_order = 1 version = "1" } } }
  39. ## Webhook Secret locals { webhook_secret = "XXXXXXXXXXXXXXXXXXXXXX" } ##

    CodePipeline Webhook resource "aws_codepipeline_webhook" "codepipeline-webhook" { name = "webhook-github" authentication = "GITHUB_HMAC" target_action = "Source" target_pipeline = "${aws_codepipeline.codepipeline.name}" authentication_configuration { secret_token = "${local.webhook_secret}" } filter { json_path = "$.ref" match_equals = "refs/heads/{Branch}" } }
  40. ## Github Webhook resource "github_repository_webhook" "repository-webhook" { repository = "aws-pipeline-example"

    name = "codepipeline-webhook" configuration { url = "${aws_codepipeline_webhook.codepipeline-webhook.url}" content_type = "json" insecure_ssl = true secret = "${local.webhook_secret}" } events = ["push"] }
  41. まとめ ・FargateへのデプロイはAWSのデプロイ3兄弟を利用しよう ・OSSと組み合わせるとさらに便利に! ・デプロイ基盤を整えておくとリリース作業を省力化できる ・皆様のデプロイ基盤構築に役立てれば幸いです

  42. END