├── .gitignore ├── .gitlab-ci.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── images ├── appmesh-eks-gitlab-cicd.jpg └── eks-appmesh-gitlabci-pipeline.png ├── infra └── README.md ├── manifests ├── mesh.yml ├── templates │ ├── deployment.yml.template │ ├── virtualnode.yml.template │ ├── virtualrouter-canary.yml.template │ └── virtualrouter.yml.template ├── virtualgateway.yml └── virtualservice.yml ├── pipeline.sh ├── src ├── Dockerfile └── app │ ├── app.py │ └── requirements.txt └── traffic.sh /.gitignore: -------------------------------------------------------------------------------- 1 | cluster_config.yaml 2 | alb-ingress-iam-policy.json 3 | kubeconfig_*.yaml 4 | kubeconfig_*.yaml* 5 | 6 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image : python:3.8.6-alpine3.11 2 | 3 | variables: 4 | DOCKER_DRIVER: overlay2 5 | APP_NAME: appmesh-app 6 | 7 | default: 8 | before_script: 9 | - | 10 | apk --update add curl=7.67.0-r1 jq=1.6-r0 bash=5.0.11-r1 11 | pip --no-cache-dir install --upgrade pip awscli==1.18.154 && aws --version && rm -rf /var/cache/apk/* 12 | 13 | export KUBECTL_VERSION=v1.19.0 14 | curl -L -o /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl 15 | chmod +x /usr/bin/kubectl 16 | kubectl version --client 17 | 18 | curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp 19 | mv /tmp/eksctl /usr/local/bin 20 | eksctl version 21 | stages: 22 | - test 23 | - publish 24 | - deploy 25 | - kill 26 | 27 | unit-test: 28 | stage: test 29 | script: 30 | - sleep 3 31 | - echo "unit-tests executed" 32 | 33 | integration-test: 34 | stage: test 35 | script: 36 | - sleep 3 37 | - echo "integration-tests executed" 38 | 39 | 40 | push_to_ecr: 41 | stage: publish 42 | image: docker:latest 43 | services: 44 | - docker:dind 45 | before_script: 46 | - | 47 | docker --version 48 | apk add --no-cache curl jq python3 py-pip && pip install awscli==1.18.154 49 | script: 50 | - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION) 51 | - export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) 52 | - echo "ACCOUNT_ID= $ACCOUNT_ID" 53 | - export REPOSITORY_URL=$ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/flask-app:${CI_PIPELINE_ID} && echo $REPOSITORY_URL 54 | - cd src/ 55 | - docker build -t $REPOSITORY_URL . 56 | - docker push $REPOSITORY_URL 57 | - docker tag $REPOSITORY_URL $ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/flask-app:latest 58 | - docker push $ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/flask-app:latest 59 | 60 | deploy%25: 61 | stage: deploy 62 | when: manual 63 | script: 64 | - export INIT_WEIGHT=75 && export NEW_WEIGHT=25 65 | - eksctl utils write-kubeconfig --kubeconfig kubeconfig-$CLUSTER_NAME.yaml --cluster $CLUSTER_NAME --region $AWS_DEFAULT_REGION 66 | - export KUBECONFIG=${PWD}/kubeconfig-$CLUSTER_NAME.yaml 67 | - chmod 775 pipeline.sh && ./pipeline.sh deploy 68 | 69 | deploy%50: 70 | stage: deploy 71 | when: manual 72 | script: 73 | - export INIT_WEIGHT=50 && export NEW_WEIGHT=50 74 | - eksctl utils write-kubeconfig --kubeconfig kubeconfig-$CLUSTER_NAME.yaml --cluster $CLUSTER_NAME --region $AWS_DEFAULT_REGION 75 | - export KUBECONFIG=${PWD}/kubeconfig-$CLUSTER_NAME.yaml 76 | - chmod 775 pipeline.sh && ./pipeline.sh deploy 77 | 78 | 79 | deploy%75: 80 | stage: deploy 81 | when: manual 82 | script: 83 | - export INIT_WEIGHT=25 && export NEW_WEIGHT=75 84 | - eksctl utils write-kubeconfig --kubeconfig kubeconfig-$CLUSTER_NAME.yaml --cluster $CLUSTER_NAME --region $AWS_DEFAULT_REGION 85 | - export KUBECONFIG=${PWD}/kubeconfig-$CLUSTER_NAME.yaml 86 | - chmod 775 pipeline.sh && ./pipeline.sh deploy 87 | 88 | 89 | deploy%100: 90 | stage: deploy 91 | when: manual 92 | script: 93 | - export INIT_WEIGHT=0 && export NEW_WEIGHT=100 94 | - eksctl utils write-kubeconfig --kubeconfig kubeconfig-$CLUSTER_NAME.yaml --cluster $CLUSTER_NAME --region $AWS_DEFAULT_REGION 95 | - export KUBECONFIG=${PWD}/kubeconfig-$CLUSTER_NAME.yaml 96 | - chmod 775 pipeline.sh && ./pipeline.sh deploy 97 | 98 | 99 | kill_previous: 100 | stage: kill 101 | when: manual 102 | script: 103 | - eksctl utils write-kubeconfig --kubeconfig kubeconfig-$CLUSTER_NAME.yaml --cluster $CLUSTER_NAME --region $AWS_DEFAULT_REGION 104 | - export KUBECONFIG=${PWD}/kubeconfig-$CLUSTER_NAME.yaml 105 | - chmod 775 pipeline.sh && ./pipeline.sh destroy 106 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## CI/CD on Amazon EKS using AWS AppMesh and Gitlab CI 2 | ![EKS AppMesh Gitlab CI/CD](images/appmesh-eks-gitlab-cicd.jpg) 3 | 4 | 5 | ##### Steps 6 | 1. Check this [manual](infra/README.md), and execute the infrastructure commands to create EKS cluster and its dependencies. 7 | 2. Create an empty repo in Gitlab 8 | 3. Put following environment variables in CI/CD Settings of created empty repo(step 2). 9 | 10 | - `CLUSTER_NAME=` 11 | - `AWS_ACCESS_KEY_ID=` 12 | - `AWS_SECRET_ACCESS_KEY=` 13 | - `AWS_DEFAULT_REGION=` 14 | 15 | 4. Add Gitlab as remote origin, then push this project into created repo in Gitlab 16 | ``` 17 | git remote set-url origin 18 | git remote -v 19 | git push origin master 20 | ``` 21 | 22 | **Sample Gitlab CI/CD Pipeline:** 23 | 24 | ![EKS AppMesh Gitlab CI/CD Pipeline](images/eks-appmesh-gitlabci-pipeline.png) 25 | 26 | 27 | ## Security 28 | 29 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 30 | 31 | ## License 32 | 33 | This library is licensed under the MIT-0 License. See the LICENSE file. 34 | 35 | -------------------------------------------------------------------------------- /images/appmesh-eks-gitlab-cicd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-appmesh-eks-gitlab-cicd/9a8425f6cca63fad57badb76fe74633612e1a029/images/appmesh-eks-gitlab-cicd.jpg -------------------------------------------------------------------------------- /images/eks-appmesh-gitlabci-pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-appmesh-eks-gitlab-cicd/9a8425f6cca63fad57badb76fe74633612e1a029/images/eks-appmesh-gitlabci-pipeline.png -------------------------------------------------------------------------------- /infra/README.md: -------------------------------------------------------------------------------- 1 | **Prerequisites for Linux & MacOsx:** 2 | 3 | - You must have `helm 3.3.0+` installed. 4 | - You must have `awscli 2.0.0+` installed. 5 | - You must have `kubectl 1.19.0+` installed. 6 | - You must have `eksctl 0.26.0+` installed. 7 | - You must have `jq 1.6+` installed. 8 | 9 | **1. Create Keypair from AWS console** 10 | 11 | Go to AWS EC2 console, create EC2 keypair and download private key. This will be used for EKS nodes later on. 12 | 13 | **2. Export following variables** 14 | 15 | `export CLUSTER_NAME=` 16 | 17 | `export REGION=(i.e. us-west-2)` 18 | 19 | **3. Create config file for EKS cluster** 20 | 21 | Replace `` and `` with yours in below yaml file, then execute it. 22 | 23 | ``` 24 | cat <<"EOF" > ./cluster_config.yml 25 | --- 26 | apiVersion: eksctl.io/v1alpha5 27 | kind: ClusterConfig 28 | metadata: 29 | name: 30 | region: us-west-2 31 | nodeGroups: 32 | - name: -workers 33 | instanceType: t3.medium 34 | desiredCapacity: 1 35 | minSize: 1 36 | maxSize: 2 37 | ssh: 38 | publicKeyName: 39 | allow: true 40 | iam: 41 | withAddonPolicies: 42 | autoScaler: true 43 | externalDNS: true 44 | albIngress: true 45 | appMesh: true 46 | appMeshPreview: true 47 | xRay: true 48 | cloudWatch: true 49 | EOF 50 | ``` 51 | 52 | **4. Create EKS cluster** 53 | 54 | EKS cluster creation will take approximately 15 min. 55 | ``` 56 | eksctl create cluster --config-file cluster_config.yaml --kubeconfig kubeconfig_$CLUSTER_NAME.yaml 57 | eksctl utils associate-iam-oidc-provider --cluster=$CLUSTER_NAME --region=$REGION --approve 58 | ``` 59 | 60 | **5. Export Kubeconfig** 61 | 62 | `export KUBECONFIG=kubeconfig_$CLUSTER_NAME.yaml` 63 | 64 | **6. Add repos for EKS, and other stable and incubator charts** 65 | 66 | ``` 67 | helm repo add stable https://kubernetes-charts.storage.googleapis.com/ 68 | helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator 69 | helm repo add eks https://aws.github.io/eks-charts 70 | helm repo update 71 | ``` 72 | 73 | **7. Install ALB Ingress controller** 74 | 75 | Create IAM Policy for ALB Ingress Controller: 76 | ``` 77 | wget -O alb-ingress-iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/master/docs/examples/iam-policy.json 78 | POLICY_ARN=`aws iam create-policy --policy-name ALBIngressControllerIAMPolicy --policy-document file://alb-ingress-iam-policy.json | jq -r ".Policy.Arn"` 79 | ``` 80 | 81 | Create service account for Alb ingress controller with policy created above 82 | ``` 83 | eksctl create iamserviceaccount \ 84 | --cluster=$CLUSTER_NAME \ 85 | --namespace=kube-system \ 86 | --name=alb-ingress-controller-$CLUSTER_NAME \ 87 | --attach-policy-arn=$POLICY_ARN \ 88 | --override-existing-serviceaccounts \ 89 | --region=$REGION \ 90 | --approve 91 | ``` 92 | Install ALB ingress controller 93 | ``` 94 | helm install incubator/aws-alb-ingress-controller --set clusterName=$CLUSTER_NAME --set autoDiscoverAwsRegion=true --set autoDiscoverAwsVpcID=true --generate-name --namespace kube-system 95 | ``` 96 | 97 | 98 | **8. Install AppMesh controller** 99 | 100 | Create service account for appmesh-controller 101 | ``` 102 | kubectl create ns appmesh-system 103 | 104 | eksctl create iamserviceaccount --cluster $CLUSTER_NAME \ 105 | --namespace appmesh-system \ 106 | --name appmesh-controller \ 107 | --attach-policy-arn arn:aws:iam::aws:policy/AWSCloudMapFullAccess,arn:aws:iam::aws:policy/AWSAppMeshFullAccess,arn:aws:iam::aws:policy/AWSAppMeshEnvoyAccess \ 108 | --override-existing-serviceaccounts \ 109 | --region=$REGION \ 110 | --approve 111 | ``` 112 | 113 | Install appmesh-controller 114 | ``` 115 | helm upgrade -i appmesh-controller eks/appmesh-controller \ 116 | --namespace appmesh-system \ 117 | --set region=$REGION \ 118 | --set serviceAccount.create=false \ 119 | --set serviceAccount.name=appmesh-controller 120 | ``` 121 | 122 | **9. Create Dynamodb table for CI/CD Versioning** 123 | 124 | This table will be used by Gitlab CI/CD in canary deployment to track previous and current versions of application 125 | ``` 126 | export TABLE_NAME=versioning 127 | export REPO_NAME=flask-app 128 | 129 | aws dynamodb create-table \ 130 | --table-name $TABLE_NAME \ 131 | --attribute-definitions \ 132 | AttributeName=app_name,AttributeType=S \ 133 | --key-schema \ 134 | AttributeName=app_name,KeyType=HASH \ 135 | --provisioned-throughput \ 136 | ReadCapacityUnits=1,WriteCapacityUnits=1 137 | 138 | aws ecr create-repository --repository-name $REPO_NAME 139 | 140 | ``` -------------------------------------------------------------------------------- /manifests/mesh.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: "appmesh-ns" 6 | labels: 7 | mesh: appmesh-mesh 8 | appmesh.k8s.aws/sidecarInjectorWebhook: enabled 9 | gateway: ingress-gw 10 | --- 11 | apiVersion: appmesh.k8s.aws/v1beta2 12 | kind: Mesh 13 | metadata: 14 | name: appmesh-mesh 15 | spec: 16 | namespaceSelector: 17 | matchLabels: 18 | mesh: appmesh-mesh 19 | -------------------------------------------------------------------------------- /manifests/templates/deployment.yml.template: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: flask-app-${APP_VERSION} 5 | labels: 6 | app: flask-app-${APP_VERSION} 7 | namespace: appmesh-ns 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: flask-app-${APP_VERSION} 13 | strategy: 14 | rollingUpdate: 15 | maxSurge: 25% 16 | maxUnavailable: 25% 17 | type: RollingUpdate 18 | template: 19 | metadata: 20 | labels: 21 | app: flask-app-${APP_VERSION} 22 | spec: 23 | containers: 24 | - image: ${ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/flask-app:${APP_VERSION} 25 | imagePullPolicy: Always 26 | name: flask-app-${APP_VERSION} 27 | ports: 28 | - containerPort: 8081 29 | -------------------------------------------------------------------------------- /manifests/templates/virtualnode.yml.template: -------------------------------------------------------------------------------- 1 | apiVersion: appmesh.k8s.aws/v1beta2 2 | kind: VirtualNode 3 | metadata: 4 | name: flask-app-${APP_VERSION} 5 | namespace: appmesh-ns 6 | spec: 7 | podSelector: 8 | matchLabels: 9 | app: flask-app-${APP_VERSION} 10 | listeners: 11 | - portMapping: 12 | port: 8081 13 | protocol: http 14 | healthCheck: 15 | protocol: http 16 | path: '/' 17 | healthyThreshold: 3 18 | unhealthyThreshold: 5 19 | timeoutMillis: 5000 20 | intervalMillis: 5000 21 | serviceDiscovery: 22 | awsCloudMap: 23 | namespaceName: appmeshworkshop.pvt.local 24 | serviceName: flask-app-${APP_VERSION} 25 | -------------------------------------------------------------------------------- /manifests/templates/virtualrouter-canary.yml.template: -------------------------------------------------------------------------------- 1 | apiVersion: appmesh.k8s.aws/v1beta2 2 | kind: VirtualRouter 3 | metadata: 4 | name: flask-router 5 | namespace: appmesh-ns 6 | spec: 7 | listeners: 8 | - portMapping: 9 | port: 8081 10 | protocol: http 11 | routes: 12 | - name: route-to-flask-app 13 | httpRoute: 14 | match: 15 | prefix: / 16 | action: 17 | weightedTargets: 18 | - virtualNodeRef: 19 | name: flask-app-${INIT_VERSION} 20 | weight: ${INIT_WEIGHT} 21 | - virtualNodeRef: 22 | name: flask-app-${CURRENT_VERSION} 23 | weight: ${NEW_WEIGHT} 24 | -------------------------------------------------------------------------------- /manifests/templates/virtualrouter.yml.template: -------------------------------------------------------------------------------- 1 | apiVersion: appmesh.k8s.aws/v1beta2 2 | kind: VirtualRouter 3 | metadata: 4 | name: flask-router 5 | namespace: appmesh-ns 6 | spec: 7 | listeners: 8 | - portMapping: 9 | port: 8081 10 | protocol: http 11 | routes: 12 | - name: route-to-flask-app 13 | httpRoute: 14 | match: 15 | prefix: / 16 | action: 17 | weightedTargets: 18 | - virtualNodeRef: 19 | name: flask-app-${INIT_VERSION} 20 | weight: ${INIT_WEIGHT} 21 | -------------------------------------------------------------------------------- /manifests/virtualgateway.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: appmesh.k8s.aws/v1beta2 3 | kind: VirtualGateway 4 | metadata: 5 | name: ingress-gw 6 | namespace: appmesh-ns 7 | spec: 8 | namespaceSelector: 9 | matchLabels: 10 | gateway: ingress-gw 11 | podSelector: 12 | matchLabels: 13 | app: ingress-gw 14 | listeners: 15 | - portMapping: 16 | port: 8088 17 | protocol: http 18 | healthCheck: 19 | protocol: http 20 | path: '/' 21 | healthyThreshold: 3 22 | unhealthyThreshold: 5 23 | timeoutMillis: 5000 24 | intervalMillis: 5000 25 | --- 26 | apiVersion: appmesh.k8s.aws/v1beta2 27 | kind: GatewayRoute 28 | metadata: 29 | name: gateway-route-flask 30 | namespace: appmesh-ns 31 | spec: 32 | httpRoute: 33 | match: 34 | prefix: "/" 35 | action: 36 | target: 37 | virtualService: 38 | virtualServiceRef: 39 | name: flask 40 | --- 41 | apiVersion: v1 42 | kind: Service 43 | metadata: 44 | name: ingress-gw 45 | namespace: appmesh-ns 46 | annotations: 47 | service.beta.kubernetes.io/aws-load-balancer-type: "nlb" 48 | spec: 49 | type: LoadBalancer 50 | ports: 51 | - port: 80 52 | targetPort: 8088 53 | name: http 54 | selector: 55 | app: ingress-gw 56 | --- 57 | apiVersion: apps/v1 58 | kind: Deployment 59 | metadata: 60 | name: ingress-gw 61 | namespace: appmesh-ns 62 | spec: 63 | replicas: 1 64 | selector: 65 | matchLabels: 66 | app: ingress-gw 67 | template: 68 | metadata: 69 | labels: 70 | app: ingress-gw 71 | spec: 72 | containers: 73 | - name: envoy 74 | image: 840364872350.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-envoy:v1.15.0.0-prod 75 | ports: 76 | - containerPort: 8088 77 | -------------------------------------------------------------------------------- /manifests/virtualservice.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: appmesh.k8s.aws/v1beta2 3 | kind: VirtualService 4 | metadata: 5 | name: flask 6 | namespace: appmesh-ns 7 | spec: 8 | awsName: flask.appmeshworkshop.hosted.local 9 | provider: 10 | virtualRouter: 11 | virtualRouterRef: 12 | name: flask-router 13 | -------------------------------------------------------------------------------- /pipeline.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function check_versioning(){ 4 | version_result=`aws dynamodb get-item --consistent-read --table-name versioning --key '{ "app_name": {"S": "'$APP_NAME'"}}'` 5 | current_ver=`echo $version_result | jq -r '.Item.current_ver.S'` 6 | init_ver=`echo $version_result | jq -r '.Item.init_ver.S'` 7 | if [ -z $current_ver ];then 8 | export CURRENT_VERSION=${CI_PIPELINE_ID} 9 | export INIT_VERSION=${CI_PIPELINE_ID} 10 | else 11 | if [ "$current_ver" != "${CI_PIPELINE_ID}" ];then 12 | export CURRENT_VERSION=${CI_PIPELINE_ID} 13 | else 14 | export CURRENT_VERSION=$current_ver 15 | fi 16 | export INIT_VERSION=$init_ver 17 | fi 18 | } 19 | 20 | check_versioning 21 | 22 | export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) 23 | export NAMESPACE=appmesh-ns 24 | 25 | echo "AWS_DEFAULT_REGION: "$AWS_DEFAULT_REGION 26 | echo "ACCOUNT_ID: "$ACCOUNT_ID 27 | echo "APP_NAME: "$APP_NAME 28 | echo "INIT VERSION: "$INIT_VERSION 29 | echo "CURRENT VERSION: "$CURRENT_VERSION 30 | echo "INIT WEIGHT: "$INIT_WEIGHT 31 | echo "NEW WEIGHT: "$NEW_WEIGHT 32 | 33 | cd manifests/ 34 | 35 | if [ $1 == "deploy" ];then 36 | export APP_VERSION=$CURRENT_VERSION && echo "APP VERSION: "$APP_VERSION 37 | 38 | # --- Mesh ---# 39 | kubectl apply -f mesh.yml 40 | 41 | # --- Virtualnode ---# 42 | eval "cat <virtualnode.yml 46 | kubectl apply -f virtualnode.yml -n $NAMESPACE 47 | 48 | # # --- Deployment ---# 49 | eval "cat <deployment.yml 53 | kubectl apply -f deployment.yml --record -n $NAMESPACE 54 | 55 | SERVICE_RESP="$(kubectl get virtualservice flask -n $NAMESPACE 2>&1)" 56 | 57 | # # --- Virtualservice ---# 58 | kubectl apply -f virtualservice.yml -n $NAMESPACE 59 | 60 | if [[ $SERVICE_RESP =~ "NotFound" ]] 61 | then 62 | echo "Service does not exists" 63 | # # --- Virtualrouter ---# 64 | eval "cat <virtualrouter.yml 68 | kubectl apply -f virtualrouter.yml -n $NAMESPACE 69 | else 70 | # # --- Virtualrouter Canary ---# 71 | eval "cat <virtualrouter.yml 75 | kubectl apply -f virtualrouter.yml -n $NAMESPACE 76 | fi 77 | 78 | # --- Virtual Ingress gw ---# 79 | kubectl apply -f virtualgateway.yml -n $NAMESPACE 80 | 81 | aws dynamodb put-item --table-name versioning \ 82 | --item '{"app_name": {"S": "'$APP_NAME'"}, "current_ver": {"S": "'$CURRENT_VERSION'"}, "init_ver": {"S": "'$INIT_VERSION'"}}' 83 | 84 | elif [ $1 == "destroy" ];then 85 | export APP_VERSION=$INIT_VERSION && echo "APP VERSION: "$APP_VERSION 86 | 87 | export INIT_VERSION=$CURRENT_VERSION 88 | export INIT_WEIGHT=100 89 | eval "cat <virtualrouter.yml 93 | kubectl apply -f virtualrouter.yml -n $NAMESPACE 94 | 95 | # --- Deployment ---# 96 | eval "cat <deployment.yml 100 | kubectl delete -f deployment.yml -n $NAMESPACE 101 | 102 | eval "cat <virtualnode.yml 106 | kubectl delete -f virtualnode.yml -n $NAMESPACE 107 | 108 | aws dynamodb put-item --table-name versioning \ 109 | --item '{"app_name": {"S": "'$APP_NAME'"}, "current_ver": {"S": "'$CURRENT_VERSION'"}, "init_ver": {"S": "'$CURRENT_VERSION'"}}' 110 | fi 111 | 112 | -------------------------------------------------------------------------------- /src/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6.10 2 | 3 | WORKDIR /app 4 | 5 | COPY app /app 6 | 7 | RUN pip install -r requirements.txt 8 | 9 | CMD python app.py 10 | 11 | EXPOSE 8081 -------------------------------------------------------------------------------- /src/app/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | app = Flask(__name__) 3 | 4 | @app.route("/") 5 | def hello(): 6 | return "Hello v1" 7 | 8 | if __name__ == "__main__": 9 | app.run(host='0.0.0.0', port=8081) 10 | -------------------------------------------------------------------------------- /src/app/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask -------------------------------------------------------------------------------- /traffic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | [[ -z $1 ]] && { echo "Url is not set as parameter!"; exit; } 4 | 5 | url=$1 6 | 7 | while true; do 8 | curl $url 9 | echo 10 | sleep .5 11 | done --------------------------------------------------------------------------------