diff --git a/lab/scripts/installer.sh b/lab/scripts/installer.sh index e70160728..1284c63ce 100644 --- a/lab/scripts/installer.sh +++ b/lab/scripts/installer.sh @@ -20,8 +20,8 @@ kubeseal_checksum='2e765b87889bfcf06a6249cde8e28507e3b7be29851e4fac651853f7638f1 yq_version='4.30.4' yq_checksum='30459aa144a26125a1b22c62760f9b3872123233a5658934f7bd9fe714d7864d' -flux_version='0.38.3' -flux_checksum='268b8d9a2fa5b0c9e462b551eaefdadb9e03370eb53061a88a2a9ac40e95e8e4' +flux_version='2.1.0' +flux_checksum='fe6d32da40d5f876434e964c46bc07d00af138c560e063fdcfa8f73e37224087' argocd_version='2.7.4' argocd_checksum='1b9a5f7c47b3c1326a622533f073cef46511e391d296d9b075f583b474780356' diff --git a/manifests/modules/automation/gitops/flux/.workshop/terraform/addon.tf b/manifests/modules/automation/gitops/flux/.workshop/terraform/addon.tf index d51ba08c2..34c8fb753 100644 --- a/manifests/modules/automation/gitops/flux/.workshop/terraform/addon.tf +++ b/manifests/modules/automation/gitops/flux/.workshop/terraform/addon.tf @@ -62,5 +62,502 @@ output "environment" { value = < + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/docs/automation/gitops/flux/assets/ecr.png b/website/docs/automation/gitops/flux/assets/ecr.png new file mode 100644 index 000000000..55dbbe2dd Binary files /dev/null and b/website/docs/automation/gitops/flux/assets/ecr.png differ diff --git a/website/docs/automation/gitops/flux/assets/ui-after.png b/website/docs/automation/gitops/flux/assets/ui-after.png new file mode 100644 index 000000000..5cad05524 Binary files /dev/null and b/website/docs/automation/gitops/flux/assets/ui-after.png differ diff --git a/website/docs/automation/gitops/flux/assets/ui-before.png b/website/docs/automation/gitops/flux/assets/ui-before.png new file mode 100644 index 000000000..e17a72a1a Binary files /dev/null and b/website/docs/automation/gitops/flux/assets/ui-before.png differ diff --git a/website/docs/automation/gitops/flux/ci.md b/website/docs/automation/gitops/flux/ci.md new file mode 100644 index 000000000..2d1a5d661 --- /dev/null +++ b/website/docs/automation/gitops/flux/ci.md @@ -0,0 +1,223 @@ +--- +title: 'Continuous Integration and GitOps' +sidebar_position: 50 +--- + +We have successfully bootstrapped Flux on EKS cluster and deployed the application. To demonstrate how to make changes in the source code an application, build a new container images and leverage GitOps to deploy a new image to a cluster we introduce Continuous Integration pipeline. We will leverage AWS Developer Tools and [DevOps principles](https://aws.amazon.com/devops/what-is-devops/) to build [multi-architecture container images](https://aws.amazon.com/blogs/containers/introducing-multi-architecture-container-images-for-amazon-ecr/) for Amazon ECR. + +We created Continuous Integration Pipeline during the prepare environment step and now we need to make it up and running. + +![CI](assets/ci-multi-arch.png) + +First, clone CodeCommit repository for the application sources: + +```bash +$ git clone ssh://${GITOPS_IAM_SSH_KEY_ID}@git-codecommit.${AWS_REGION}.amazonaws.com/v1/repos/${EKS_CLUSTER_NAME}-retail-store-sample ~/environment/retail-store-sample-codecommit +``` + +Next, populate the CodeCommit repository with the sources from the public repository of the [Sample application](https://github.com/aws-containers/retail-store-sample-app): + +```bash +$ git clone https://github.com/aws-containers/retail-store-sample-app ~/environment/retail-store-sample-app +$ git -C ~/environment/retail-store-sample-codecommit checkout -b main +$ cp -R ~/environment/retail-store-sample-app/src ~/environment/retail-store-sample-codecommit +$ cp -R ~/environment/retail-store-sample-app/images ~/environment/retail-store-sample-codecommit +``` + +We use AWS CodeBuild and define `buildspec.yml` to build new `x86_64` and `arm64` images in parallel. + +```file +manifests/modules/automation/gitops/flux/buildspec.yml +``` + +```bash +$ cp ~/environment/eks-workshop/modules/automation/gitops/flux/buildspec.yml ~/environment/retail-store-sample-codecommit/buildspec.yml +``` + +We use AWS CodeBuild also to build `Image Index` for `multi-architecture image` using `buildspec-manifest.yml` + +```file +manifests/modules/automation/gitops/flux/buildspec-manifest.yml +``` + +```bash +$ cp ~/environment/eks-workshop/modules/automation/gitops/flux/buildspec-manifest.yml ~/environment/retail-store-sample-codecommit/buildspec-manifest.yml +``` + +Now we are ready to push our changes to CodeCommit and start the CodePipeline + +```bash +$ git -C ~/environment/retail-store-sample-codecommit add . +$ git -C ~/environment/retail-store-sample-codecommit commit -am "initial commit" +$ git -C ~/environment/retail-store-sample-codecommit push --set-upstream origin main +``` +You can navigate to `CodePipeline` in AWS Console and explore `eks-workshop-retail-store-sample` pipeline. + +![ci-start](assets/ci-start.png) + +As a result of a CodePipeline run with CodeBuild you will have a new image in ECR + +```bash +$ echo IMAGE_URI_UI=$IMAGE_URI_UI +``` + +The suffix `z7llv2` in the name `retail-store-sample-ui-z7llv2` is random and will be different in your case. + +![ci-start](assets/ecr.png) + +While we are waiting for pipeline to create new images (5-10 minutes), let's [automate image updates to Git](https://fluxcd.io/flux/guides/image-update/) using Flux Image Automation Controller. + +First, we need to install Flux components. + +```bash +$ flux install --components-extra=image-reflector-controller,image-automation-controller +``` + +Next, edit file `deployment.yaml` and add placeholder for new container image url + +```bash +$ git -C ~/environment/flux pull +$ sed -i 's/^\(\s*\)image: "public.ecr.aws\/aws-containers\/retail-store-sample-ui:0.4.0"/\1image: "public.ecr.aws\/aws-containers\/retail-store-sample-ui:0.4.0" # {"$imagepolicy": "flux-system:ui"}/' ~/environment/flux/apps/ui/deployment.yaml +$ less ~/environment/flux/apps/ui/deployment.yaml | grep imagepolicy + image: "public.ecr.aws/aws-containers/retail-store-sample-ui:0.4.0" # {"$imagepolicy": "flux-system:ui"} +``` + +Change to: + +image: "public.ecr.aws/aws-containers/retail-store-sample-ui:0.4.0" `# {"$imagepolicy": "flux-system:ui"}` + +Commit changes to deployment: + +```bash +$ git -C ~/environment/flux add . +$ git -C ~/environment/flux commit -am "Adding ImagePolicy" +$ git -C ~/environment/flux push +``` + +We need to deploy custom resource definitions (ImageRepository, ImagePolicy, ImageUpdateAutomation) for Flux to enable monitoring of new container images in ECR and automated deployment using GitOps. + +1. ImageRepository: + +```file +manifests/modules/automation/gitops/flux/imagerepository.yaml +``` + +2. ImagePolicy: + +```file +manifests/modules/automation/gitops/flux/imagepolicy.yaml +``` + +3. ImageUpdateAutomation: + +```file +manifests/modules/automation/gitops/flux/imageupdateautomation.yaml +``` + +```bash +$ cp ~/environment/eks-workshop/modules/automation/gitops/flux/image*.yaml ~/environment/retail-store-sample-codecommit/ +$ yq -i ".spec.image = env(IMAGE_URI_UI)" ~/environment/retail-store-sample-codecommit/imagerepository.yaml +$ less ~/environment/retail-store-sample-codecommit/imagerepository.yaml | grep image: +$ kubectl apply -f ~/environment/retail-store-sample-codecommit/imagerepository.yaml +$ kubectl apply -f ~/environment/retail-store-sample-codecommit/imagepolicy.yaml +$ kubectl apply -f ~/environment/retail-store-sample-codecommit/imageupdateautomation.yaml +``` + +We created the following architecture: + +![ci-eks-gitops](assets/ci-eks-gitops.png) + +Now, lets reconcile the changes. + +```bash +$ flux reconcile image repository ui +$ flux reconcile source git flux-system +$ flux reconcile kustomization apps +$ kubectl wait deployment -n ui ui --for condition=Available=True --timeout=120s +$ git -C ~/environment/flux pull +$ kubectl -n ui get pods +``` + +We can check that `image:` in the `deployment` has been updated to a new tag. + +```bash +$ kubectl -n ui describe deployment ui | grep Image +``` + +To access `UI` using a browser we need to expose it using `Ingress` and `Load Balancer`. + +Let's create an Ingress resource with the following manifest: + +```file +manifests/modules/exposing/ingress/creating-ingress/ingress.yaml +``` + +This will cause the AWS Load Balancer Controller to provision an Application Load Balancer and configure it to route traffic to the Pods for the `ui` application. + +```bash timeout=180 +$ kubectl apply -k ~/environment/eks-workshop/modules/exposing/ingress/creating-ingress +``` + +Let's inspect the Ingress object created: + +```bash +$ kubectl get ingress ui -n ui +NAME CLASS HOSTS ADDRESS PORTS AGE +ui alb * k8s-ui-ui-1268651632.us-west-2.elb.amazonaws.com 80 15s +``` + +We wait 2-5 minutes until Application Load Balancer will be provisioned and check the UI page using url of the ingress. + +```bash timeout=300 +$ export UI_URL=$(kubectl get ingress -n ui ui -o jsonpath="{.status.loadBalancer.ingress[*].hostname}{'\n'}") +$ wait-for-lb $UI_URL +``` + +![ui-before](assets/ui-before.png) + +Let's introduce changes to the source code of the Sample Application. + +Edit the file: + +```bash +$ sed -i 's/\(^\s*\)Retail Store Sample/\1Retail Store Sample New/' ~/environment/retail-store-sample-codecommit/src/ui/src/main/resources/templates/fragments/layout.html +$ less ~/environment/retail-store-sample-codecommit/src/ui/src/main/resources/templates/fragments/layout.html | grep New +``` + +Change line 24 + +`Retail Store Sample` to `Retail Store Sample New` + +Commit changes. + +```bash +$ git -C ~/environment/retail-store-sample-codecommit status +$ git -C ~/environment/retail-store-sample-codecommit add . +$ git -C ~/environment/retail-store-sample-codecommit commit -am "Update UI src" +$ git -C ~/environment/retail-store-sample-codecommit push +``` + +Wait until CodePipeline will build the new image and Flux will deploy it. + +```bash timeout=900 +$ kubectl -n ui describe deployment ui | grep Image +$ while [[ "$(aws codepipeline get-pipeline-state --name eks-workshop-retail-store-sample --query 'stageStates[1].actionStates[0].latestExecution.status' --output text)" != "InProgress" ]]; do echo "Waiting for pipeline to start ..."; sleep 10; done && echo "Pipeline started." +$ while [[ "$(aws codepipeline get-pipeline-state --name eks-workshop-retail-store-sample --query 'stageStates[1].actionStates[2].latestExecution.status' --output text)" != "Succeeded" ]]; do echo "Waiting for pipeline to reach 'Succeeded' state ..."; sleep 10; done && echo "Pipeline has reached the 'Succeeded' state." + +$ flux reconcile image repository ui +$ sleep 5 +$ flux reconcile source git flux-system +$ flux reconcile kustomization apps +$ kubectl wait deployment -n ui ui --for condition=Available=True --timeout=120s +$ git -C ~/environment/flux pull +$ kubectl -n ui get pods + +$ kubectl -n ui describe deployment ui | grep Image + +$ export UI_URL=$(kubectl get ingress -n ui ui -o jsonpath="{.status.loadBalancer.ingress[*].hostname}{'\n'}") +$ wait-for-lb $UI_URL +``` + +After successful build and deployment (5-10 minutes) we will have the new version of UI application up and running. + +![ui-after](assets/ui-after.png) diff --git a/website/docs/automation/gitops/flux/index.md b/website/docs/automation/gitops/flux/index.md index b6a6e7d54..1438aadf1 100644 --- a/website/docs/automation/gitops/flux/index.md +++ b/website/docs/automation/gitops/flux/index.md @@ -14,6 +14,7 @@ $ prepare-environment automation/gitops/flux This will make the following changes to your lab environment: - Create an AWS CodeCommit repository - Create an IAM user with access to the CodeCommit repository +- Create Continuous Integration Pipeline for [Sample Application UI](https://github.com/aws-containers/retail-store-sample-app) You can view the Terraform that applies these changes [here](https://github.com/VAR::MANIFESTS_OWNER/VAR::MANIFESTS_REPOSITORY/tree/VAR::MANIFESTS_REF/manifests/modules/networking/custom-networking/.workshop/terraform).