$30 off During Our Annual Pro Sale. View Details »

Why Containerize?

Why Containerize?

Talk about the need for containerization and the tenets of micro-services architecture. Containerize an application consisting of three services and build/run it using docker-compose. Explain Dockerfile, docker-compose file and what happens behind the scenes in detail.

Rupak Ganguly

April 18, 2020
Tweet

More Decks by Rupak Ganguly

Other Decks in Technology

Transcript

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

    View Slide

  2. 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

    View Slide

  3. MICRO-SERVICES
    breaking the monolith

    View Slide


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

    View Slide

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

    View Slide

  6. 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

    View Slide

  7. STORE APP
    containerizing the store app

    View Slide

  8. 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

    View Slide

  9. 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

    View Slide

  10. 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)

    View Slide

  11. 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.

    View Slide

  12. 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

    View Slide

  13. DEMO
    running the store app

    View Slide

  14. 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

    View Slide

  15. 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...

    View Slide

  16. 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

    View Slide

  17. 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

    View Slide

  18. 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

    View Slide

  19. 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

    View Slide

  20. 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

    View Slide

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

    View Slide