Deployments

Deploying your app can be a complex task. You have to decide between a VPS (virtual private server) or a standardized managed solution. By abstracting and modularizing your deployments, you enable your service to scale up much quicker, and help ensure you are not using any patterns that are not best practice.

Managed solutions reduce the need to figure out the complexities of setting up server software, but will limit you on the amount of customization and expandability of your service.

Containers and Orchestration

Virtual machines, containers, and bare metal all have their use cases, but they all do essentially the same thing: run software. I won’t go into the differences on this page, but just know that our abstraction of concepts should help remove most of the details surrounding the different environments.

We’ll focus on what we’ll call containers. Containers allow you to quickly spin up a customized set of preconfigured software independent of whatever you already have installed, so you shouldn’t run into any conflicts. Generally, you’ll see people using Docker images to form their containers.

Creating an image

You need to figure out what software your service needs to operate, what storage it may need, and what network access it needs. You also need to figure out how your software will know how to be configured, where its storage is, and what ports it should bind to. These could be in a configuration file, environment variables, or even some mix of those two with a configuration service that handles the registration and configuration.

This goes back to some ideas of composition, each part needs to do something specific. Deployments set up and update your service (and may optionally automatically start it), Now, in the deployment it’ll need to download the correct version, unpack it, and modify files. All of those steps also have specific steps.

This is not a tutorial on how to create a deployment image, but on how to apply programming abstraction concepts to DevOps.

Docker Compose

Docker compose can give us an easy look into how you might need to abstract out your deployments. Take this example that sets up a service and a Postgres database.

version: '3.3'
services:
    postgres:
        restart: always
        volumes:
            - 'pgdata:/var/lib/postgresql/data'
        image: postgres
        environment:
            - POSTGRES_USER=postgres
            - POSTGRES_PASSWORD=postgres
            - POSTGRES_DB=dbname
            - PGUSER=postgres
        ports:
            - "5432:5432"
        healthcheck:
            test: ["CMD-SHELL", "pg_isready"]
            interval: 1s
            timeout: 5s
            retries: 10
        networks:
            - 'net'
    service:
        ports:
            - '80:80'
        restart: always
        image: service
        networks:
            - 'net'
        depends_on:
            - 'postgres'
        healthcheck:
            test: ["CMD", "curl", "-f", "http://localhost:80"]
            interval: 10s
            timeout: 10s
            retries: 5
volumes:
    pgdata: {}
networks:
    net: {}

Even if you’re not familiar with docker or the docker compose syntax, you can get an idea of what’s going on here. We have simple definitions for the network, credentials, and health checks. This may look a little different depending on your orchestration setup, but if you image having multiple “service” containers (multiple nodes running simultaneously), you can see why it’s helpful to make your service modular and abstract.