+ - 0:00:00
Notes for current slide
Notes for next slide

Developing and Testing Microservices
with Flask, React, and Docker

microservices


Presented by Michael Herman at PyTennessee logo
1 / 83

Agenda (part 1)

⏱ ~ 1 hour

2 / 83

Agenda (part 1)

⏱ ~ 1 hour

(1) Intro
  1. About Me
  2. Objectives
  3. Architecture
  4. Project Setup
  5. Why Microservices?
3 / 83

Agenda (part 1)

⏱ ~ 1 hour

(1) Intro
  1. About Me
  2. Objectives
  3. Architecture
  4. Project Setup
  5. Why Microservices?
(2) Containers and Services
  1. Users DB (postgres)
  2. Users API (flask)
  3. Client (react)
  4. Hot Reload
  5. Nginx
  6. End-to-End Tests
  7. Docker Machine
  8. EC2 Deployment
4 / 83

Agenda (part 2)

⏱ ~ 1 hour

5 / 83

Agenda (part 2)

⏱ ~ 1 hour

(3) Orchestration
  1. What is Container Orchestration?
  2. Why ECS?
  3. Orchestration Feature Wish-list
  4. Elastic Load Balancing (ELB)
  5. Elastic Container Registry (ECR)
  6. Elastic Container Service (ECS)
  7. Zero-downtime Deploy Demo
6 / 83

Agenda (part 2)

⏱ ~ 1 hour

(3) Orchestration
  1. What is Container Orchestration?
  2. Why ECS?
  3. Orchestration Feature Wish-list
  4. Elastic Load Balancing (ELB)
  5. Elastic Container Registry (ECR)
  6. Elastic Container Service (ECS)
  7. Zero-downtime Deploy Demo
(4) Goodbye
  1. Next Steps
  2. Questions
7 / 83

About Michael

$ whoami
michael.herman
8 / 83

About Michael

$ whoami
michael.herman

Day Job:

Software Engineer at ClickFox.   clickfox logo

9 / 83

About Michael

$ whoami
michael.herman

Day Job:

Software Engineer at ClickFox.   clickfox logo

Docker:

  1. Avid Docker user since 2014.
  2. Last year I architected and set up On-Demand Environments With Docker and AWS ECS.
10 / 83

About Michael

$ whoami
michael.herman

Day Job:

Software Engineer at ClickFox.   clickfox logo

Docker:

  1. Avid Docker user since 2014.
  2. Last year I architected and set up On-Demand Environments With Docker and AWS ECS.

Also:

  1. Co-founder/author of Real Python
  2. 😍 - tech writing/education, open source, financial models, radiohead

me

11 / 83

Objectives

By the end of this talk, you should be able to...

12 / 83

Objectives

By the end of this talk, you should be able to...

Containerization

  1. Configure and run microservices locally with Docker
  2. Utilize volumes to mount code into a container to enable hot reload
  3. Run unit and integration tests inside a Docker container
  4. Secure services via JWT-based authentication
  5. Configure React, Jest, and Enzyme to work with Docker
  6. Test the entire set of services with functional, end-to-end tests
13 / 83

Objectives

By the end of this talk, you should be able to...

Containerization

  1. Configure and run microservices locally with Docker
  2. Utilize volumes to mount code into a container to enable hot reload
  3. Run unit and integration tests inside a Docker container
  4. Secure services via JWT-based authentication
  5. Configure React, Jest, and Enzyme to work with Docker
  6. Test the entire set of services with functional, end-to-end tests

Orchestration

  1. Explain what container orchestration is and why you may need to incorporate an orchestration tool into your deployment process
  2. Discuss the pros and cons of using Elastic Container Service (ECS) over other orchestration tools like Kubernetes, Mesos, and Docker Swarm
  3. Configure an Application Load Balancer along with ECS to run a set of microservices
  4. Integrate ECR into the deployment process
  5. Send container logs to CloudWatch
14 / 83

TestDriven.io

Much of this tutorial comes from the following course I wrote at Testdriven.io...


microservice tech

Microservices with Docker, Flask, and React

Along with learning how to build the underlying code bases from each service, you'll also be introduced to more advanced topics like:

  • AWS Lambda + API Gateway
  • React PropTypes
  • Redux
  • Blue/Green Deploys
  • CI/CD
testdriven.io
15 / 83

Architecture

https://github.com/testdrivenio/testdriven-app-2.2/tree/pytn

Name Container Tech
Users API users Flask, gunicorn
Users DB users-db Postgres
Client client React, React-Router
Nginx nginx Nginx
e2e Tests N/A TestCafe
microservice tech
17 / 83

Architecture

https://github.com/testdrivenio/testdriven-app-2.2/tree/pytn

Name Container Tech
Users API users Flask, gunicorn
Users DB users-db Postgres
Client client React, React-Router
Nginx nginx Nginx
e2e Tests N/A TestCafe
microservice tech

In general, services are...

  1. Organized around domain
  2. Easy to replace (ideally stateless)
  3. Implemented using different technologies
18 / 83

Project Setup

19 / 83

Project Setup

Fire up the app locally:

$ git clone https://github.com/testdrivenio/testdriven-app-2.2 \
--branch pytn --single-branch
$ cd testdriven-app-2.2
$ export REACT_APP_USERS_SERVICE_URL=http://localhost
$ docker-compose -f docker-compose-dev.yml up -d --build

NOTE: Using Docker Machine? Replace localhost above with DOCKER_MACHINE_IP.

20 / 83

Project Setup

Fire up the app locally:

$ git clone https://github.com/testdrivenio/testdriven-app-2.2 \
--branch pytn --single-branch
$ cd testdriven-app-2.2
$ export REACT_APP_USERS_SERVICE_URL=http://localhost
$ docker-compose -f docker-compose-dev.yml up -d --build

NOTE: Using Docker Machine? Replace localhost above with DOCKER_MACHINE_IP.

Docker Compose

An orchestration tool for running multi-container apps.

Often, when developing applications with a microservice architecture, you cannot fully test out all services until you deploy to a staging server. This takes much too long to get feedback. Docker helps to speed up this process by making it easier to link together small, independent services locally.

Docker 101: http://mherman.org/docker-workshop

docker compose logo

21 / 83

Why Microservices?

22 / 83

Why Microservices?

Pros

  1. Separation of Concerns: different apps can have different code bases and dependencies, localized errors, less coupling can lead to easier scaling
  2. Smaller Code Bases: without having to grasp the entire system, it's often easier to understand the code base
23 / 83

Why Microservices?

Pros

  1. Separation of Concerns: different apps can have different code bases and dependencies, localized errors, less coupling can lead to easier scaling
  2. Smaller Code Bases: without having to grasp the entire system, it's often easier to understand the code base

Cons

  1. Design Complexity: microservices are complex, start with modules
  2. Network Complexity: many helper functions become AJAX calls, ping-pong-like effect in terms of network requests, network lag
  3. Data Persistence: managing state (DBs, queues, service discovery) is hard
  4. Security: more surface area = more areas prone to attack
  5. Integration Tests: testing is hard, especially if you try to test like you'd test a monolith
24 / 83

Why Microservices?

Pros

  1. Separation of Concerns: different apps can have different code bases and dependencies, localized errors, less coupling can lead to easier scaling
  2. Smaller Code Bases: without having to grasp the entire system, it's often easier to understand the code base

Cons

  1. Design Complexity: microservices are complex, start with modules
  2. Network Complexity: many helper functions become AJAX calls, ping-pong-like effect in terms of network requests, network lag
  3. Data Persistence: managing state (DBs, queues, service discovery) is hard
  4. Security: more surface area = more areas prone to attack
  5. Integration Tests: testing is hard, especially if you try to test like you'd test a monolith

microservice

You need - Strong communication + docs, mature devops, lots of planning

More on microservices: https://testdriven.io/part-one-microservices

25 / 83

Containerization

26 / 83

Users DB

testdriven-users-db
27 / 83

Users DB

https://github.com/testdrivenio/testdriven-app-2.2/tree/pytn/services/users/project/db

Steps:

  1. Review Dockerfile and docker-compose-dev.yml
  2. Build image, run container:

    $ docker-compose -f docker-compose-dev.yml up -d --build users-db
  3. Test/Sanity Check:

    $ docker exec -ti users-db psql -U postgres -W
postgres logo
28 / 83

Users API

testdriven-users
29 / 83

Users API

https://github.com/testdrivenio/testdriven-app-2.2/tree/pytn/services/users

Steps:

  1. Review the code, Dockerfile-dev, and docker-compose-dev.yml
  2. Build image, run container:

    $ docker-compose -f docker-compose-dev.yml up -d --build users
  3. Test/Sanity Check:

    # create and seed the db
    $ docker-compose -f docker-compose-dev.yml \
    run users python manage.py recreate_db
    $ docker-compose -f docker-compose-dev.yml run users python manage.py seed_db
    # run unit and integration tests
    $ docker-compose -f docker-compose-dev.yml run users python manage.py test

    Navigate to http://localhost:5000 in your browser.

flask logo
30 / 83

Client

testdriven-web
31 / 83

Client

https://github.com/testdrivenio/testdriven-app-2.2/tree/pytn/services/client

Steps:

  1. Review the code, Dockerfile-dev, Dockerfile-prod, and docker-compose-dev.yml

  2. Build image, run container:

    # add env variable
    $ export REACT_APP_USERS_SERVICE_URL=http://localhost
    # build and run:
    $ docker-compose -f docker-compose-dev.yml up -d --build client
  3. Test/Sanity Check:

    Navigate to http://localhost:3007 in your browser


react logo
32 / 83

Hot Reload

To test hot reload, first open the Docker logs:

$ docker-compose -f docker-compose-dev.yml logs -f [container-name]
33 / 83

Hot Reload

To test hot reload, first open the Docker logs:

$ docker-compose -f docker-compose-dev.yml logs -f [container-name]

Make a change to the code, watch the logs update!

$ docker-compose -f docker-compose-dev.yml logs -f users
Attaching to users
users | Waiting for postgres...
users | PostgreSQL started
users | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
users | * Restarting with stat
users | * Debugger is active!
users | * Debugger PIN: 133-923-613
users | * Detected change in '/usr/src/app/project/api/auth.py', reloading
users | * Restarting with stat
users | * Debugger is active!
users | * Debugger PIN: 133-923-613
34 / 83

Hot Reload

To test hot reload, first open the Docker logs:

$ docker-compose -f docker-compose-dev.yml logs -f [container-name]

Make a change to the code, watch the logs update!

$ docker-compose -f docker-compose-dev.yml logs -f users
Attaching to users
users | Waiting for postgres...
users | PostgreSQL started
users | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
users | * Restarting with stat
users | * Debugger is active!
users | * Debugger PIN: 133-923-613
users | * Detected change in '/usr/src/app/project/api/auth.py', reloading
users | * Restarting with stat
users | * Debugger is active!
users | * Debugger PIN: 133-923-613
docker logo

For more helpful commands, review https://testdriven.io/part-one-workflow

35 / 83

Nginx

testdriven-nginx
36 / 83

Nginx

https://github.com/testdrivenio/testdriven-app-2.2/tree/pytn/services/nginx

Steps:

  1. Review the code, Dockerfile-dev, and docker-compose-dev.yml

  2. Build image, run container:

    $ docker-compose -f docker-compose-dev.yml up -d --build nginx
  3. Test/Sanity Check: navigate to http://localhost


nginx logo
37 / 83

End-to-End Tests

testdriven-e2e
38 / 83

End-to-End Tests

https://github.com/testdrivenio/testdriven-app-2.2/tree/pytn/e2e

Notes:

  1. These are not containerized 😢
  2. Check out the TestCafe 101 @ http://mherman.org/testcafe-example

Steps:

  1. Review the code and docker-compose-prod.yml

  2. Update the containers, then test:

    $ docker-compose -f docker-compose-prod.yml up -d --build
    # add env variable
    $ export TEST_URL=http://localhost
    # create db
    $ docker-compose -f docker-compose-prod.yml \
    run users python manage.py recreate_db
    # run tests
    $ testcafe chrome e2e
testcafe logo
39 / 83

Docker Machine

40 / 83

Docker Machine

Assuming you already have an AWS account setup along with IAM and your AWS credentials are stored in an ~/.aws/credentials file, create a new host on an EC2 instance:

$ docker-machine create --driver amazonec2 pytn
41 / 83

Docker Machine

Assuming you already have an AWS account setup along with IAM and your AWS credentials are stored in an ~/.aws/credentials file, create a new host on an EC2 instance:

$ docker-machine create --driver amazonec2 pytn

Once done, set it as the active host and point the Docker client at it:

$ docker-machine env pytn
$ eval $(docker-machine env pytn)
42 / 83

Docker Machine

Assuming you already have an AWS account setup along with IAM and your AWS credentials are stored in an ~/.aws/credentials file, create a new host on an EC2 instance:

$ docker-machine create --driver amazonec2 pytn

Once done, set it as the active host and point the Docker client at it:

$ docker-machine env pytn
$ eval $(docker-machine env pytn)

Grab the IP address associated with the new EC2 instance and use it to set the REACT_APP_USERS_SERVICE_URL environment variable:

$ docker-machine ip pytn
$ export REACT_APP_USERS_SERVICE_URL=http://DOCKER_MACHINE_IP

NOTE: The REACT_APP_USERS_SERVICE_URL environment variable must be set at the build-time, so it is available before we kick off Create React App's production build process.

43 / 83

EC2 Deployment

44 / 83

EC2 Deployment

Set the secret key:

$ export SECRET_KEY=my_precious
45 / 83

EC2 Deployment

Set the secret key:

$ export SECRET_KEY=my_precious

Build the images, spin up the containers:

$ docker-compose -f docker-compose-prod.yml up -d --build
46 / 83

EC2 Deployment

Set the secret key:

$ export SECRET_KEY=my_precious

Build the images, spin up the containers:

$ docker-compose -f docker-compose-prod.yml up -d --build

Create and seed the database:

$ docker-compose -f docker-compose-prod.yml \
run users python manage.py recreate_db
$ docker-compose -f docker-compose-prod.yml run users python manage.py seed_db
47 / 83

EC2 Deployment

Set the secret key:

$ export SECRET_KEY=my_precious

Build the images, spin up the containers:

$ docker-compose -f docker-compose-prod.yml up -d --build

Create and seed the database:

$ docker-compose -f docker-compose-prod.yml \
run users python manage.py recreate_db
$ docker-compose -f docker-compose-prod.yml run users python manage.py seed_db

Update the TEST_URL environment variable and then run the e2e tests:

$ testcafe chrome e2e
aws logo

For more, review https://docs.docker.com/machine/examples/aws/.

48 / 83

Orchestration

49 / 83

What is Container Orchestration?

50 / 83

What is Container Orchestration?

As you move from deploying containers on a single machine to deploying them across a number of machines, you need an orchestration tool to manage the arrangement and coordination of the containers across the entire system.

51 / 83

What is Container Orchestration?

As you move from deploying containers on a single machine to deploying them across a number of machines, you need an orchestration tool to manage the arrangement and coordination of the containers across the entire system.

This is where ECS fits in along with a number of other orchestration tools - like Kubernetes, Mesos, and Docker Swarm.

52 / 83

What is Container Orchestration?

As you move from deploying containers on a single machine to deploying them across a number of machines, you need an orchestration tool to manage the arrangement and coordination of the containers across the entire system.

This is where ECS fits in along with a number of other orchestration tools - like Kubernetes, Mesos, and Docker Swarm.



Which one?

kubernetes vs docker swarm vs mesos
53 / 83

Why ECS?

54 / 83

Why ECS?

ECS is simpler to set up and easier to use and you have the full power of AWS behind it, so you can easily integrate it into other AWS services (which we will be doing shortly). In short, you get scheduling, service discovery, load balancing, and auto-scaling out-of-the-box. Plus, you can take full advantage of EC2’s multiple availability-zones.

55 / 83

Why ECS?

ECS is simpler to set up and easier to use and you have the full power of AWS behind it, so you can easily integrate it into other AWS services (which we will be doing shortly). In short, you get scheduling, service discovery, load balancing, and auto-scaling out-of-the-box. Plus, you can take full advantage of EC2’s multiple availability-zones.

If you’re already on AWS and have no desire to leave, then it makes sense to use AWS.

56 / 83

Why ECS?

ECS is simpler to set up and easier to use and you have the full power of AWS behind it, so you can easily integrate it into other AWS services (which we will be doing shortly). In short, you get scheduling, service discovery, load balancing, and auto-scaling out-of-the-box. Plus, you can take full advantage of EC2’s multiple availability-zones.

If you’re already on AWS and have no desire to leave, then it makes sense to use AWS.

Keep in mind, that ECS is often lagging behind Kubernetes, in terms of features, though. If you’re looking for the most features and portability and you don’t mind installing and managing the tool, then Kubernetes, Docker Swarm, or Mesos may be right for you.

57 / 83

Why ECS?

ECS is simpler to set up and easier to use and you have the full power of AWS behind it, so you can easily integrate it into other AWS services (which we will be doing shortly). In short, you get scheduling, service discovery, load balancing, and auto-scaling out-of-the-box. Plus, you can take full advantage of EC2’s multiple availability-zones.

If you’re already on AWS and have no desire to leave, then it makes sense to use AWS.

Keep in mind, that ECS is often lagging behind Kubernetes, in terms of features, though. If you’re looking for the most features and portability and you don’t mind installing and managing the tool, then Kubernetes, Docker Swarm, or Mesos may be right for you.

One last thing to take note of is that since ECS is closed-source, there isn’t a true way to run an environment locally in order to achieve development-to-production parity. (LocalStack?)


Awesome comparison resource -> https://blog.kublr.com/choosing-the-right-containerization-and-cluster-management-tool-fdfcec5700df

58 / 83

Orchestration Feature Wish-list

Most orchestration tools come with a core set of features. You can find those features below along with the associated AWS service...

orchestration features

We'll either cover the features with a ✔️ directly or you'll see them in action from the demo.

59 / 83

Elastic Load Balancing (part 1)

The Elastic Load Balancer distributes incoming application traffic and scales resources as needed to meet traffic needs.

60 / 83

Elastic Load Balancing (part 1)

The Elastic Load Balancer distributes incoming application traffic and scales resources as needed to meet traffic needs.

It's one of (if not) the most important parts of your applications since it needs to always be up, routing traffic to healthy back-ends, and ready to scale at a moment’s notice.

61 / 83

Elastic Load Balancing (part 1)

The Elastic Load Balancer distributes incoming application traffic and scales resources as needed to meet traffic needs.

It's one of (if not) the most important parts of your applications since it needs to always be up, routing traffic to healthy back-ends, and ready to scale at a moment’s notice.

(1) Application Load Balancer

There are currently three types of Elastic Load Balancers to choose from. We’ll be using the Application Load Balancer since it provides support for path-based routing and dynamic port-mapping and it also enables zero-downtime deployments.

62 / 83

Elastic Load Balancing (part 1)

The Elastic Load Balancer distributes incoming application traffic and scales resources as needed to meet traffic needs.

It's one of (if not) the most important parts of your applications since it needs to always be up, routing traffic to healthy back-ends, and ready to scale at a moment’s notice.

(1) Application Load Balancer

There are currently three types of Elastic Load Balancers to choose from. We’ll be using the Application Load Balancer since it provides support for path-based routing and dynamic port-mapping and it also enables zero-downtime deployments.

(2) Target Groups and (3) Listeners

Target Groups are attached to the Application Load Balancer and are used to route traffic to the containers found in the ECS service.

Listeners are added to the load balancer, which are then forwarded to a specific Target Group.

63 / 83

Elastic Load Balancing (part 2)

The Application Load Balancer is one of those AWS services that makes ECS so powerful. In fact, before it’s release, ECS was not a viable orchestration solution.

elastic load balancing

https://console.aws.amazon.com/ec2

64 / 83

ECR

Before you can start spinning up containers, you need to set up EC2 Container Registry (ECR), a private image registry. Once setup, you can then build, tag, and push images.

65 / 83

ECR

Before you can start spinning up containers, you need to set up EC2 Container Registry (ECR), a private image registry. Once setup, you can then build, tag, and push images.

Images

Set up the following images at https://console.aws.amazon.com/ecs:

  1. pytn-users
  2. pytn-users_db
  3. pytn-client
66 / 83

ECR

Before you can start spinning up containers, you need to set up EC2 Container Registry (ECR), a private image registry. Once setup, you can then build, tag, and push images.

Images

Set up the following images at https://console.aws.amazon.com/ecs:

  1. pytn-users
  2. pytn-users_db
  3. pytn-client

Why did we leave out Nginx?

67 / 83

ECR

Before you can start spinning up containers, you need to set up EC2 Container Registry (ECR), a private image registry. Once setup, you can then build, tag, and push images.

Images

Set up the following images at https://console.aws.amazon.com/ecs:

  1. pytn-users
  2. pytn-users_db
  3. pytn-client

Why did we leave out Nginx?

Tagging

When tagging your images, you should think about version control (using the SHA1 to tie the image back to a specific commit) as well as the environment (development, staging, production) the image should belong to.

/$PROJECT/$ENVIRONMENT:$SHA1

68 / 83

ECS (part 1)

The Elastic Container Service (ECS) has four main components:

  1. Task Definitions
  2. Tasks
  3. Services
  4. Clusters
69 / 83

ECS (part 1)

The Elastic Container Service (ECS) has four main components:

  1. Task Definitions
  2. Tasks
  3. Services
  4. Clusters

Task Definitions => Tasks => Services => Clusters

ecs

70 / 83

ECS (part 2)

71 / 83

ECS (part 2)

Task Definitions (1)

Task Definitions define which containers make up the overall application and how much resources are allocated to each container. You can think of them as blueprints.

72 / 83

ECS (part 2)

Task Definitions (1)

Task Definitions define which containers make up the overall application and how much resources are allocated to each container. You can think of them as blueprints.

(2) Tasks and (3) Services

Services instantiate the containers from the Task Definitions and run them on EC2 boxes within an ECS Cluster. Such instances are called Tasks.

73 / 83

ECS (part 2)

Task Definitions (1)

Task Definitions define which containers make up the overall application and how much resources are allocated to each container. You can think of them as blueprints.

(2) Tasks and (3) Services

Services instantiate the containers from the Task Definitions and run them on EC2 boxes within an ECS Cluster. Such instances are called Tasks.

(4) Cluster

An ECS Cluster is just a group of EC2 container instances managed by ECS.

74 / 83

Zero-downtime Deploy Demo

76 / 83

Zero-downtime Deploy Demo

Steps

  1. Make a quick change to the app locally.
  2. Build, tag, and push the new images.
  3. Add a new revision to the task definition.
  4. Update the service.
77 / 83

Zero-downtime Deploy Demo

Steps

  1. Make a quick change to the app locally.
  2. Build, tag, and push the new images.
  3. Add a new revision to the task definition.
  4. Update the service.

What happens next?

  1. Once you update the Service, ECS will pick up on these changes and instantiate the Task Definitions, creating new Tasks that will spin up on the Cluster instances.
  2. ALB will run health checks on the new instances once they are up.
    • If the health checks pass, traffic is forwarded appropriately to the new Tasks while the old Tasks are spun down.
    • If the health checks fail, the new Tasks are spun down.
78 / 83

Zero-downtime Deploy Demo

Steps

  1. Make a quick change to the app locally.
  2. Build, tag, and push the new images.
  3. Add a new revision to the task definition.
  4. Update the service.

What happens next?

  1. Once you update the Service, ECS will pick up on these changes and instantiate the Task Definitions, creating new Tasks that will spin up on the Cluster instances.
  2. ALB will run health checks on the new instances once they are up.
    • If the health checks pass, traffic is forwarded appropriately to the new Tasks while the old Tasks are spun down.
    • If the health checks fail, the new Tasks are spun down.

The health checks are the last line of defense after your unit, integration, and functional tests.

79 / 83

That's it!

What's next?

80 / 83

That's it!

What's next?

Check your understanding
  1. Add the Swagger service
  2. Configure Postgres via RDS
  3. Add the remaining features from the Orchestration Feature Wish-list.
81 / 83

That's it!

What's next?

Check your understanding
  1. Add the Swagger service
  2. Configure Postgres via RDS
  3. Add the remaining features from the Orchestration Feature Wish-list.
Resources
  1. Slides - http://mherman.org/presentations/pytn-2018
  2. Repo - https://github.com/testdrivenio/testdriven-app-2.2/tree/pytn
  3. Testdriven.io - full course! ❤️
  4. How to Build 12 Factor Microservices on Docker
  5. Docker Cheat Sheet
testdriven.io
82 / 83

That's it!

What's next?

Check your understanding
  1. Add the Swagger service
  2. Configure Postgres via RDS
  3. Add the remaining features from the Orchestration Feature Wish-list.
Resources
  1. Slides - http://mherman.org/presentations/pytn-2018
  2. Repo - https://github.com/testdrivenio/testdriven-app-2.2/tree/pytn
  3. Testdriven.io - full course! ❤️
  4. How to Build 12 Factor Microservices on Docker
  5. Docker Cheat Sheet
testdriven.io
Questions?

✌️

83 / 83

Agenda (part 1)

⏱ ~ 1 hour

2 / 83
Paused

Help

Keyboard shortcuts

↑, ←, Pg Up, k Go to previous slide
↓, →, Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
Number + Return Go to specific slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow