Slide 1

Slide 1 text

WHY CONTAINERIZE? what & why of containerization of apps Rupak Ganguly April 18th, 2020

Slide 2

Slide 2 text

AGENDA Micro-services Tenets of micro-services Store App Architecture Local app architecture Containerized app architecture (composing services) Containerization the Store App Building the App Docker Image (Dockerfile) Running the App in containers (compose file) Behind the scenes of a docker-compose Demo Commands

Slide 3

Slide 3 text

MICRO-SERVICES breaking the monolith

Slide 4

Slide 4 text

“ Microservices architecture essentially follows the Unix philosophy of "Do one thing and do it well"

Slide 5

Slide 5 text

MONOLITHIC TO MICRO-SERVICES https://martinfowler.com/articles/microservices.html

Slide 6

Slide 6 text

THE SERVICE MINDSET ➤ Independent unit of functionality (separation of concerns) ➤ Organized around business capabilities ➤ One process and communicate with lightweight mechanisms ➤ Autonomously developed (has its own SDLC) ➤ Polyglot in nature (various programming languages) ➤ Different data storage technologies ➤ Independently versioned ➤ Independently deployable ➤ Built/Deployed via automated processes (CI/CD) ➤ Easily scaled up/down based on criteria

Slide 7

Slide 7 text

STORE APP containerizing the store app

Slide 8

Slide 8 text

THE LOCAL STORE APP Frontend Web (react app) Products API (nodejs app) Database (mongo db) Local Development Environment Frontend Web Products API Database Port: 27017 Port: 5000 Port: 3000 Overlay Network

Slide 9

Slide 9 text

COMPOSING SERVICES Frontend Web Products API Database 27017 8081:5000 8080:3000 Host Port:Container Port Overlay Network docker-compose up Note: The database port is NOT exposed to the host since the database is only required to be accessed by the Products API service. That makes the database access secured. services: web: build: context: ./basic-react-project ports: - 8080:3000 depends_on: - mongo - api api: build: context: ./MyNodeJsProject ports: - 8081:5000 depends_on: - mongo healthcheck: mongo: image: mongo:3.6.3 ports: - "27017" volumes: - api-mongo-db:/data/db

Slide 10

Slide 10 text

DOCKERFILE FROM node:12.16.1-alpine ARG BUILD_ENV=development ENV APP_SOURCE_DIR=/some/path RUN apk --no-cache add bash curl WORKDIR $APP_SOURCE_DIR COPY . $APP_SOURCE_DIR CMD ["npm", "start"] A Dockerfile is a declarative way to express how to build your service or app into a Docker image that can then be run as a container. A Docker image is immutable and can be tagged to represent a snapshot (like a version). FROM: specifies the base image for your application. In this case we are using the node:12.16.1 image that provides node. ARG: specifies the build arguments that can passed via a build command to customize the build. e.g. docker build -—build-args BUILD_ENV=production —t myimage:1.0 . ENV: specifies the runtime environment variable that can be passed to the docker run command. e.g. docker run -e APP_SOURCE_DIR=/another/path myapp RUN: specifies the commands that you need to execute to install the software that you want in your image WORKDIR: specifies the working directory and all commands thereafter will use that COPY: used to copy files from current folder to the container CMD: specifies the command that will be run when a container starts. See ENTRYPOINT as well. Building a Docker image: docker build -t myimage:1.0 . (the . at the end represents the path of the Dockerfile)

Slide 11

Slide 11 text

DOCKER-COMPOSE.YML services: web: build: context: ./basic-react-project ports: - 8080:3000 depends_on: - mongo - api api: build: context: ./MyNodeJsProject ports: - 8081:5000 depends_on: - mongo healthcheck: mongo: image: mongo:3.6.3 ports: - "27017" volumes: - api-mongo-db:/data/db A docker compose file is a declarative way to express services that make up an application. It is an YAML file and in plain text. services: list all services that make up the app web: represents the service ‘web’ and its corresponding configuration build: specifies how to build the service using a path to the code image: instead of building the service, use an already built image ports: represents the ports for the service ‘host port: container port’ depends_on: represents the dependent services for the service healthcheck: configures a command used to validate that a service is ‘healthy’ volumes: is used for a stateful service to persist data after a container exits. It creates a bridge between the host and the container. The bridge is two-way i.e. data written on the host is available on the container and vice- versa.

Slide 12

Slide 12 text

BEHIND THE SCENES services: web: build: context: ./basic-react-project ports: - 8080:3000 depends_on: - mongo - api api: build: context: ./MyNodeJsProject ports: - 8081:5000 depends_on: - mongo healthcheck: mongo: image: mongo:3.6.3 ports: - "27017" volumes: - api-mongo-db:/data/db When you run docker-compose up, the following happens: 1.A network named storeapp_default is created by default 2.A container named storeapp_web_1 is created 3.A container named storeapp_api_1 is created 4.A container named storeapp_mongo_1 is created 5.All the services joins the network storeapp_default ➤App is named after the directory it lives in but can be overridden by the -p flag ➤The default network is named _default i.e. storeapp_default ➤Each container for a service joins the default network, ➤and is both reachable by other containers on that network, ➤and discoverable by them at a hostname identical to the container name. ➤Networked service-to-service communication use the CONTAINER_PORT. ➤When HOST_PORT is defined, the service is accessible outside the swarm as well. ➤Within the storeapp_web_1 container, your connection string to Mongo database would look like mongodb://mongo:27017/ docker-compose -p storeapp up

Slide 13

Slide 13 text

DEMO running the store app

Slide 14

Slide 14 text

DOCKER COMPOSE COMMANDS Build images from Dockerfile and then run the app interactively: docker-compose up —build Run the app in background (daemon): docker-compose up -d List the containers: docker-compose ps Set number of containers for a service (scale up/down): docker-compose up --scale = Stop and remove containers, networks, images, and volumes: docker-compose down

Slide 15

Slide 15 text

DEMO COMMANDS - UP WITH BUILD Build images from Dockerfile and then run the app interactively: docker-compose up —build Creating network "storeapp_default" with the default driver Building api Step 1/19 : FROM node:12.16.2-alpine Successfully tagged storeapp_api:latest Building web Step 1/19 : FROM node:12.16.2-alpine Successfully tagged storeapp_web:latest Creating storeapp_mongo_1 ... done Creating storeapp_api_1 ... done Creating storeapp_web_1 ... done Attaching to storeapp_mongo_1, storeapp_api_1, storeapp_web_1 mongo_1 | 2020-04-17T08:21:49.284+0000 I CONTROL [initandlisten] MongoDB starting mongo_1 | 2020-04-17T08:21:49.285+0000 I CONTROL [initandlisten] db version v3.6.3 api_1 | $ nodemon server.js api_1 | [nodemon] starting `node server.js` web_1 | $ react-scripts start api_1 | Server running on port 5000 web_1 | Starting the development server...

Slide 16

Slide 16 text

DEMO COMMANDS - UP Run the app in background (daemon): docker-compose up -d Starting storeapp_mongo_1 ... done Starting storeapp_api_1 ... done Starting storeapp_web_1 ... done List the containers: docker-compose ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c0f3471a3ae6 storeapp_web "docker-entrypoint.s " 6 seconds ago Up 3 seconds (health: starting) 0.0.0.0:8080->3000/tcp storeapp_web_1 f8150d450359 storeapp_api "docker-entrypoint.s " 7 seconds ago Up 5 seconds (health: starting) 0.0.0.0:8081->5000/tcp storeapp_api_1 309a9f2cd5f7 mongo:3.6.3 "docker-entrypoint.s " 8 seconds ago Up 6 seconds (health: starting) 0.0.0.0:27017->27017/tcp storeapp_mongo_1

Slide 17

Slide 17 text

DEMO COMMANDS - SCALING (PORT CONFLICTS) Set number of containers for a service (scale up/down): docker-compose up --scale api=3 WARNING: The "api" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash. Starting storeapp_api_1 ... done Creating storeapp_api_2 ... Creating storeapp_api_3 ... Creating storeapp_api_2 ... error WARNING: Host is already in use by another container ERROR: for storeapp_api_3 Cannot start service api: driver failed programming external connectivity on endpoint storeapp_api_3 (664b85882427d28ed4a694d7b46042128c590328e3d2e9bc6057f281371c0428): Bind for 0.0.0.0:8081 failed: port is already allocated ERROR: for storeapp_api_2 Cannot start service api: driver failed programming external connectivity on endpoint storeapp_api_2 (70d6c8df937a93e476ef8adf001c1a3c42ee270648321182029811eaaceee72e): Bind for 0.0.0.0:8081 failed: port is already allocated ERROR: for api Cannot start service api: driver failed programming external connectivity on endpoint storeapp_api_3 (664b85882427d28ed4a694d7b46042128c590328e3d2e9bc6057f281371c0428): Bind for 0.0.0.0:8081 failed: port is already allocated api: ports: - 8081:5000

Slide 18

Slide 18 text

DEMO COMMANDS - SCALING (DYNAMIC PORTS) Set number of containers for a service (scale up/down): docker-compose up --scale api=3 Creating network "storeapp_default" with the default driver Creating storeapp_mongo_1 ... done Creating storeapp_api_1 ... done Creating storeapp_api_2 ... done Creating storeapp_api_3 ... done Creating storeapp_web_1 ... done docker-compose ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ff68c5d9741d storeapp_web "docker-entrypoint.s " 7 seconds ago Up 5 seconds (health: starting) 0.0.0.0:8080->3000/tcp storeapp_web_1 f6da8ba063b1 storeapp_api "docker-entrypoint.s " 10 seconds ago Up 6 seconds (health: starting) 0.0.0.0:32774->5000/tcp storeapp_api_1 6f2d277985c9 storeapp_api "docker-entrypoint.s " 10 seconds ago Up 6 seconds (health: starting) 0.0.0.0:32773->5000/tcp storeapp_api_3 e395e272d360 storeapp_api "docker-entrypoint.s " 10 seconds ago Up 7 seconds (health: starting) 0.0.0.0:32772->5000/tcp storeapp_api_2 8a370985695a mongo:3.6.3 "docker-entrypoint.s " 11 seconds ago Up 9 seconds (health: starting) 0.0.0.0:27017->27017/tcp storeapp_mongo_1 api: ports: - 5000

Slide 19

Slide 19 text

DEMO COMMANDS - DOWN Stop and remove containers, networks, images, and volumes: docker-compose down Stopping storeapp_web_1 ... done Stopping storeapp_api_1 ... done Stopping storeapp_mongo_1 ... done Removing storeapp_web_1 ... done Removing storeapp_api_1 ... done Removing storeapp_mongo_1 ... done Removing network storeapp_default

Slide 20

Slide 20 text

RESOURCES What is a container: https://www.docker.com/resources/what-container Getting started with Docker: https://docs.docker.com/get-started/overview/ Install Docker: https://www.docker.com/products/docker-desktop Docker Developer Tools: https://www.docker.com/products/developer-tools Docker Engine: https://docs.docker.com/engine/ Docker Compose: https://docs.docker.com/compose/ Docker Hub: https://docs.docker.com/docker-hub/ Docker Enterprise Platform: https://docs.docker.com/ee/ Docker Kubernetes Service: https://docs.docker.com/ee/#docker-kubernetes-service

Slide 21

Slide 21 text

QUESTIONS? @rupakg rupakganguly.com Slides: https://speakerdeck.com/rupakg/why-containerize