An open API service indexing awesome lists of open source software.

https://github.com/jmhbnz/cloud-native-bootcamp

A choose your own adventure style cloud native bootcamp, created for Summer of Tech NZ. Designed to be run over a two hour session.
https://github.com/jmhbnz/cloud-native-bootcamp

aws cloud docker gcp kubernetes

Last synced: 3 months ago
JSON representation

A choose your own adventure style cloud native bootcamp, created for Summer of Tech NZ. Designed to be run over a two hour session.

Awesome Lists containing this project

README

          

# -*- ii: ii; -*-
#+TITLE: ANZ Cloud Native Bootcamp
#+AUTHOR: James Blair
#+EMAIL: james.blair@anz.com
#+DATE: [2020-05-09 Sat]

Welcome to the first ANZ Cloud Native Bootcamp for 2020!

** TODO Setting the scene
SCHEDULED: <2020-05-18 Mon 10:05>

*** TODO Introductions

Firstly some quick introductions, my name is James Blair. I'm an Automation Lead at ANZ New Zealand based in Wellington. I've been in the tech industry for eight years, most of that working within government at Inland Revenue and joined ANZ just over a year ago.

To introduce this session, I first want to go back to a particular, nostalgic memory of my childhood which is reading Goosebumps choose your own adventure novels by R.L. Stine. We all remember these right?

[[./images/goosebumps.jpg]]

Ok so rest assured my goal for the session today isn't to scare you! However I am hoping we can go on something like an adventure, as we explore cloud native together, so what I've done is set this workshop up in a choose your own adventure style, with a series of decisions along the way.

These decisions will relate to how we approach developing an application, and on which cloud provider(s) we deploy that application.

As a final note this is intended to be a brief introductory session run over two hours so is intentionally light on detail or nuance in a lot of areas. If you are already a cloud native expert then this probably won't be the session for you.

*** TODO Rules of engagement

Before we begin, for this style of workshop to run smoothly, we need to cover some key messages:

- *Everyone participates* - At each step of this adventure, we all need to collectively vote on the next step we take. To do that we'll be using the polls feature in zoom. Let's test that now to ensure it works for everyone. Additionally as we progress through our journey there will be opportunities to get hands on.

- *Asking questions* - The aim of this session is to be as interactive as possible, please don't hold questions to the end, I'm happy to answer questions as we go :)

- *Resources* - All materials from this workshop will be publicly available on my gitlab and a link provided in chat at the end of our session.

- *Technology* - For demonstrations and hands on segments we will always be working as one group. To navigate through our adventure and run code we'll be using a technique called [[https://en.wikipedia.org/wiki/Literate_programming][literate programming]] which for some quick history was formed by Donald Knuth in 1984. Essentially what this involves is using a development environment such as ~emacs~ with ~org-mode~ to weave our adventure and choices into the flow of processes and code we work through. Additionally we'll be using a tool called ~tmate~ which will allow us to all pair together and share the same development environment and terminals. I've taken to calling what we'll be doing today /*literate pair programming*/.


*** TODO Demonstration of literate programming

I'm going to change my screen layout now in Zoom so you can see what I call our pairing "left eye" and "right eye" which are just terminals. The left eye runs our ~emacs~ development environment. The right eye is the terminal we will be actually running our commands and code in.

Let's take this opportunity to test connectivity with ~tmate~. Can you all please:

- Open two new browser windows and arrange them side by side
- Navigate to the left eye [[https://tmate.io/t/x]]
- Navigate to the right eye [[https://tmate.io/t/x]]
- In the right eye type ~echo [your first name]~

*** TODO Questions before we begin

Again before we start our journey, does anyone have any questions or have any issues connecting with ~tmate~?


** TODO Starting our adventure
SCHEDULED: <2020-05-18 Mon 10:20>

So here you are, a week into a new Summer of Tech internship at ANZ and you've been assigned to one of our cloud squads. You've been tasked with helping to migrate an internal application into a scalable cloud native service that can be run on a public cloud provider such as Google or AWS.

The application in question is a basic pdf conversion app written in python which is currently running on a virtual machine on premises.

To get underway you [[What cloud native means][start by looking up what "cloud native" means]]

** TODO What cloud native means
SCHEDULED: <2020-05-18 Mon 10:25>

You make a start by looking up what "cloud native" means, finding your way to the [[https://github.com/cncf/toc/blob/master/DEFINITION.md][definition]] approved by the [[https://www.cncf.io/][Cloud Native Computing Foundation]] in 2018:

#+begin_quote
"Cloud native technologies empower organizations to build and run scalable applications in modern, dynamic environments such as public, private, and hybrid clouds. Containers, service meshes, microservices, immutable infrastructure, and declarative APIs exemplify this approach.

These techniques enable loosely coupled systems that are resilient, manageable, and observable. Combined with robust automation, they allow engineers to make high-impact changes frequently and predictably with minimal toil.

The Cloud Native Computing Foundation seeks to drive adoption of this paradigm by fostering and sustaining an ecosystem of open source, vendor-neutral projects. We democratize state-of-the-art patterns to make these innovations accessible for everyone."
#+end_quote

A wordy official definition, so from my perspective, when I'm talking about cloud native computing generally what we're talking about is code that runs in [[https://www.docker.com/][docker]] containers, is orchestrated by [[https://kubernetes.io/][kubernetes]] and runs on a public cloud provider like Google or Amazon Web Services.

Now that you've had a look at what cloud native means you [[Why cloud native is important][take a look at why it's important]].

** TODO Why cloud native is important :decision:
SCHEDULED: <2020-05-18 Mon 10:30>

Following some brief research you find it's not enough to just "lift and shift" a business application to simply operate in the cloud. Instead to take advantage of the scalability and elasticity of the cloud the business application needs to be re-architected to ensure that cloud is a core part of the design process.

You know you could really easily spin up a virtual machine in the cloud and manually install python in order to run our application, but you know that would not make the application cloud native. Along the way you find a great meme on that topic:

[[./images/dilbert.jpg]]

Memes aside, it's time to make a start on re-architecting our application to be cloud native. You know you could transform the application to use serverless infrastructure, or you could run the application in a container on a managed kubernetes cluster, do you:

- [[Going serverless][1 - Decide to go with serverless]]
- [[Going kubernetes][2 - Decide to go with kubernetes]]

** TODO Going serverless
SCHEDULED: <2020-05-18 Mon 10:35>

Serverless architecture is taking off across the globe. You know that it's easy way deploy single functions to any of the major cloud providers.

One of the common misconceptions is that serverless is only for simple code functions, major cloud providers now support running [[https://cloud.google.com/blog/products/application-development/5-principles-for-cloud-native-architecture-what-it-is-and-how-to-master-it][stateless]] containers in a serverless fashion as well.

[[./images/serverless.jpg]]

Memes aside, it's time to make a start, you know that the first step to running an application like this serverless is getting your application [[Building a docker container image][built into a docker container image]].

** TODO Going kubernetes
SCHEDULED: <2020-05-18 Mon 10:35>

Kubernetes (aka k8s) is the open source container orchestration system that is becoming ubiquitous across the planet, it was original created by Google and released in 2015 alongside the creation of the [[https://cncf.io][Cloud Native Computing Foundation]].

You know it can automate the deployment, management and scaling of container based applications so you figure it would be a good option for moving our business application to a cloud native architecture.

Taking a look at an overview [[https://www.cloudtp.com/doppler/managed-container-services-vs-bring-your-own-container-stack/][article]] you know all the major cloud providers offer a managed kubernetes service and there are also on premise kubernetes solutions available so containers can now be easily run in the cloud or on premises.

[[./images/kubernetes.jpg]]

Memes aside, it's time to make a start, you know that the first step to running an application on kubernetes is getting your application [[Building a docker container image][built into a docker container image]].

** TODO Building a docker container image :decision:
SCHEDULED: <2020-05-18 Mon 10:40>

You make a start on building a docker image for your application. For a quick refresher you take a quick look at some context on what a container is.

#+NAME: Container description
#+begin_quote
"Containers are a way to package software (e.g. web server, proxy, batch process worker) so that you can run your code and all of its dependencies in a resource isolated process. You might be thinking, "Wait, isn't that a virtual machine (VM)?" Containers virtualize the operating system, while VMs virtualize the hardware. Containers provide isolation, portability and repeatability, so your developers can easily spin up an environment and start building without the heavy lifting. More importantly, containers ensure your code runs in the same way anywhere, so if it works on your laptop, it will also work in production."
- Source [[https://github.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/tree/master/workshop-1][aws github]].
#+end_quote

Our first step to building a docker container image is creating a [[https://docs.docker.com/engine/reference/builder/][Dockerfile]]. A quick look at the docs explains what a Dockerfile is.

#+NAME: Dockerfile description
#+begin_quote
"Docker can build images automatically by reading the instructions from a Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using docker build users can create an automated build that executes several command-line instructions in succession."
#+end_quote

To make a start on creating a dockerfile you clone down the existing application code to take a look.

#+NAME: Clone the current application
#+begin_src tmate
# Clone the existing application
git clone https://gitlab.jamma.life/jmhbnz/cloud-native-bootcamp.git /tmp/cloud-native-bootcamp

# Navigate to the cloned folder
cd /tmp/cloud-native-bootcamp/pdf-app

# Look at the contents of the folder
ls -l
#+end_src

You can see one of your squad members had already started drafting a Dockerfile, however they had been pulled to another project and could not finish it. Let's take a look at that [[./pdf-app/Dockerfile][Dockerfile]].

Review the contents of the file and you'll see a few comments indicating what still needs to be done. Comments are denoted by a "#".

Once you finish the Dockerfile you decide it's time to give it a test, that's where the [[https://docs.docker.com/engine/reference/commandline/build/][docker build]] command comes in so you give it a try. You note the trailing period in the build command which tells docker to look in the current directory for the Dockerfile.

#+NAME: Build the docker image
#+begin_src tmate
# Build the docker image
docker build -t pdf-app .
#+end_src

Reviewing the ouput of the build you can see the a ~successfully built~ and ~successfully tagged~ message so you know the image built successfully, from here do you

- [[Testing a docker container image locally][1 - Try and test the application locally]]
- [[Pushing a docker container image][2 - Skip testing and push the image to the cloud]]

** TODO Testing a docker container image locally
SCHEDULED: <2020-05-18 Mon 11:00>

Before you push the newly created docker container image to a cloud registry you decide to run it locally to test that the application runs successfully. You take a look at the docs for the [[https://docs.docker.com/engine/reference/run/][docker run]] command to run the image.

You find that you need to specific the ~-p~ parameter to provide a port that the python web server running in the container will be accessible on.

#+NAME: Run the container image
#+begin_src tmate
docker run -d --name "pdf-app" -p 3000:3000 pdf-app
#+end_src

You can tell that the application is running successfully by looking at the logs and seeing that no errors are present and also using the ~docker ps~ command to verify that the container is running.

#+NAME: Review container logs
#+begin_src tmate
# Check the container logs
docker logs pdf-app

# Check the container state
docker ps -f name=pdf-app
#+end_src

Another test you can run is ensuring that the pdf conversion service still works. You know the service works by using the [[https://www.tutorialspoint.com/http/http_methods.htm][HTTP POST method]] to send a non pdf file to the application. The application should respond to the POST request with a converted PDF file.

You know that the application is running locally on port ~3000~ so let's try POSTing a word document to it using the ~curl~ command.

#+NAME: Convert a file to pdf
#+begin_src tmate
# Navigate to the example files folder
cd ../files

# Show what is in the files directory before the test
ls -l

# Post a word file to the convert endpoint
curl -o Memo.pdf -F format=pdf -F 'file=@Important Memo.docx' http://localhost:3000/convert

# Show what is in the files directory after the test
ls -l
#+end_src

After finishing testing you clean up by stopping and removing the locally running container.

#+NAME: Stop the running container
#+begin_src tmate
# Stop the running container
docker stop pdf-app

# Remove the container
docker rm pdf-app
#+end_src

With some local testing complete you feel confident to [[Pushing a docker container image][push your newly built container image to the cloud]].

** TODO Pushing a docker container image :decision:
SCHEDULED: <2020-05-18 Mon 11:15>

After building the container image you decide it's time to push it to the cloud, you have the choice of pushing it to the container registries in Amazon Web Services or Google Cloud Platform, you decide on:

- [[Google Container Registry][1 - Google Container Registry]]
- [[Amazon Elastic Container Registry][2 - Amazon Elastic Container Registry]]
- [[3 - Both!?]]

*** TODO Google Container Registry :decision:

Doing some reading online you come across the [[https://cloud.google.com/container-registry/docs/pushing-and-pulling][documentation for pushing images to Google Container Registry]]. This outlines that after configuring our local docker to authenticate with Google Container Registry we can then tag a local image with a ~[HOSTNAME]/[PROJECT-ID]/[IMAGE]~.

You can see that the standard hostname for Google Container Registry is ~gcr.io~, you have a project ID in Google Cloud already of ~cloud-native-bootcamp-277000~ and our image is called ~pdf-app~, so you tag the image with the following command.

#+NAME: Tag image for Google Container Registry and push
#+begin_src tmate
# Configure authentication for docker
echo "y" | gcloud auth configure-docker

# Tag our local image
docker tag pdf-app gcr.io/cloud-native-bootcamp-277000/pdf-app

# Push the image
docker push gcr.io/cloud-native-bootcamp-277000/pdf-app
#+end_src

You can see output confirming all layers of the image have been pushed so know that the command was successfull. Checking the [[https://console.cloud.google.com/gcr/images/cloud-native-bootcamp-277000/GLOBAL/pdf-app?gcrImageListsize=30][Google Cloud Console]] you can also see the image is now pushed.

Now that you have a container image pushed to the cloud ready to be deployed, you have second thoughts on your earlier decision, are you certain you want to:

- [[Deploy a kubernetes cluster][1 - Deploy the container on kubernetes]]
- [[Deploy a serverless application][2 - Deploy the container serverless]]

*** TODO Amazon Elastic Container Registry :decision:

Looking at the [[https://docs.aws.amazon.com/AmazonECR/latest/userguide/getting-started-cli.html][documentation for AWS Elastic Container Registry]] you see the step by step commands for using the registry via the command line. This involves setting up authentication, creating a repostitory and then pushing an image.

#+NAME: Tag image for AWS Elastic Container Registry and push
#+begin_src tmate
# Configure authentication for docker
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 088596787314.dkr.ecr.us-east-1.amazonaws.com

# Create a repository
aws ecr create-repository \
--repository-name pdf-app \
--image-scanning-configuration scanOnPush=false \
--region us-east-1

# Tag our local image
docker tag pdf-app 088596787314.dkr.ecr.us-east-1.amazonaws.com/pdf-app

# Push the image
docker push 088596787314.dkr.ecr.us-east-1.amazonaws.com/pdf-app
#+end_src

You can see the output confirming all layers of the image have been pushed so know that the command was successful. Checking the [[https://console.aws.amazon.com/ecr/repositories/pdf-app/?region=us-east-1][AWS Console]] you can also see that we have an image pushed.

Now that you have a container image pushed to the cloud ready to be deployed, you have second thoughts on your earlier decision, are you certain you want to:

- [[Deploy a kubernetes cluster][1 - Deploy the container on kubernetes]]
- [[Deploy a serverless application][2 - Deploy the container serverless]]

** TODO Deploy a kubernetes cluster :decision:
SCHEDULED: <2020-05-18 Mon 11:15>

After pushing your newly created container image to the cloud, you're ready to spin up a k8s cluster to deploy the image into. Before you get to far into that you decide it's time to refresh on [[https://en.wikipedia.org/wiki/Kubernetes][what kubernetes is]] before you proceed.

Now that you know what kubernetes is you know you have the choice of running the cluster in either Amazon Web Services or Google Cloud Platform, after evaluating the options you decide on:

- [[Google Kubernetes Engine][1 - Google Kubernetes Engine]]
- [[Amazon Elastic Kubernetes Service][2 - Amazon Elastic Kubernetes Service]]

*** TODO Google Kubernetes Engine :decision:

Taking a look at the [[https://cloud.google.com/kubernetes-engine/][overview of Google Kubernetes Engine]] you can see it is a fully managed kubernetes service, with automated upgrades and high availability, perfect for your important business application.

This is the first kubernetes cluster you've created so you're faced with a dilemma, do you create it manually using the [[https://console.cloud.google.com/][Google Cloud Console]] web interface, or in an automated way with the [[https://cloud.google.com/sdk/][Google Cloud SDK Command Line]]?

- [[Google Cloud Console][1 - Create the cluster manually with Google Cloud Console]]
- [[Google Cloud SDK Command Line][2 - Google Cloud SDK Command Line]]

**** TODO Google Cloud Console

Given this is the first time you've deployed a kubernetes cluster on Google Cloud Platform you decide to step through it manually in the [[https://console.cloud.google.com][web console]].

1. After loading up the console you navigate to *Kubernetes Engine > Clusters* in the left hand menu underneath the *Compute* header.

2. Once the clusters page has loaded you click *Create Cluster* and update the cluster name to ~company-cluster~ and specify he region as ~australia-southeast1-a~. Keeping all other settings at their defaults you click *Create* at the bottom of the page.

3. After waiting several minutes you can see the cluster has been created successfully. Clicking into the cluster you click on the *Nodes* tab to see that all three cluster nodes area ~Ready~ status.

With a cluster up and running you're ready to [[Deploy an app on kubernetes]]!

**** TODO Google Cloud SDK Command Line

You're keen to ensure anything you do today will be easy to recreate in future and be easily automated so you decide to create the cluster with the command line.

Taking a look at the [[https://cloud.google.com/kubernetes-engine/docs/how-to/creating-a-cluster#gcloud][cluster creation docs]] you can see an example gcloud command so you decide to give that a go...

#+NAME: Create and check gke cluster
#+begin_src tmate
# Create the cluster
gcloud container clusters create company-cluster --zone australia-southeast1-a

# Obtain cluster credentials
gcloud container clusters get-credentials company-cluster --zone australia-southeast1-a

# List nodes in cluster
kubectl get nodes

# List pods in cluster
kubectl get pods
#+end_src

With a cluster up and running you're ready to [[Deploy an app on kubernetes]]!

*** TODO Amazon Elastic Kubernetes Service :decision:

Taking a look at the [[https://aws.amazon.com/eks/][overview of Amazon Elastic Kubernetes Service] you can see it is a fully managed kubernetes service with high availability and strong integration with a host of other AWS services.

This is the first cluster you've created so you're faced with a dilemma, do you create it manually using the [[https://aws.amazon.com/console][AWS Web Console]], or in an automated fashion with the [[https://aws.amazon.com/cli/][AWS Command Line Interface]]?

- [[Amazon Web Services Console][1 - Create the cluster manually with the Amazon Web Services Console]]
- [[Amazon Web Services Command Line Interface][2 - Create the cluster automatically with the Amazon Web Services CLI]]

**** TODO Amazon Web Services Console

Given this is the first time you've deployed an ecs cluster on AWS you decide to step through it manually in the [[https://aws.amazon.com/console][web console]].

1. After loading up the console you search for *eks* and click into *Elastic Kubernetes Service* in the results.

2. You enter the cluster name ~company-cluster~ in the textbox on the right hand side and click *Create Cluster*.

3. You leave all settings at their default and click *Next* through to the confirmation screen then click *Create*.

4. After a brief wait you can see that the cluster is running, clicking through to the *Compute* tab you're surprised to see no cluster nodes showing!?

Faced with unexpected complexity you decide to [[Google Kubernetes Engine][take Google Kubernetes Engine for a spin]].

**** TODO Amazon Web Services Command Line Interface

You're keen to ensure anything you do today will be easy to recreate in future and be easily automated so you decide to create the cluster with the command line.

Taking a look at the [[https://docs.aws.amazon.com/eks/latest/userguide/create-cluster.html][cluster creation docs]] you can see an example aws cli command so you decide to give that a go...

#+NAME: Create and check eks cluster
#+begin_src tmate
# Create the cluster
aws eks --region us-east-1 create-cluster \
--name company-cluster \
--role-arn arn:aws:iam::088596787314:role/EKSTest \
--resources-vpc-config \
subnetIds=subnet-cdb35492,subnet-a59e7f84

# Create a kubeconfig entry for the cluster
aws eks --region us-east-1 update-kubeconfig --name company-cluster

# Check the cluster nodes
kubectl get nodes
#+end_src

Faced with unexpected complexity you decide to [[Google Kubernetes Engine][take Google Kubernetes Engine for a spin]].

** TODO Deploy a serverless application
SCHEDULED: <2020-05-18 Mon 11:15>

Coming soon! For now you return to [[Deploy a kubernetes cluster]].

** TODO Deploy an app on kubernetes
SCHEDULED: <2020-05-18 Mon 11:30>

Now that our image is in a cloud container registry, and we have a functional kubernetes cluster ready to go, let's create a gke deployment for our important pdf conversion application.

Taking a look at the [[https://console.cloud.google.com/kubernetes/workload/deploy?cluster=company-cluster&location=australia-southeast1-a&project=cloud-native-bootcamp-277000][web console]] you can see an option available to create a deployment, so you decide to give that a go. After selecting the pdf-app image and providing an application name you click *Deploy*. After a short wait you can see a pod is up and running :)

** TODO Teardown cloud resources
SCHEDULED: <2020-05-18 Mon 11:55>

To prevent unintended costs you know it's always important to ensure any cloud resources you have deployed that are not neccessary should be turned off or deleted.

Let's tear down the cloud resources we deployed.

#+NAME: Teardown kubernetes clusters
#+begin_src tmate
# Teardown google kubernetes engine cluster
gcloud container clusters delete company-cluster --zone=australia-southeast1-a --quiet

# Teardown amazon elastic kubernetes service cluster
#aws eks --region us-east-1 delete-cluster --name company-cluster
#+end_src