Skip to content

Instantly share code, notes, and snippets.

@ackertyson
Last active August 8, 2018 22:45
Show Gist options
  • Save ackertyson/f3d45cd204398c81231d0f2de030b1a0 to your computer and use it in GitHub Desktop.
Save ackertyson/f3d45cd204398c81231d0f2de030b1a0 to your computer and use it in GitHub Desktop.
A quick how-to for using common docker, docker-compose and docker-machine commands in an example NodeJS app (with remote deployment).

DOCKER GUIDE

A quick how-to for using common docker, docker-compose and docker-machine commands in an example NodeJS app which has different builds for development and production and is deployed to a remote Docker host. Does NOT require uploading your app images to any damn public registries! Or to any registry at all, for that matter!

Setup

The commands below assume that your dev compose file runs your app build tasks (gulp, etc.). See example project files below.

You'll need the following .bashrc aliases:

alias dclean='docker rm $(docker ps -f status=exited -a -q); docker rmi $(docker images -f dangling=true -a -q); docker volume rm $(docker volume ls -f dangling=true -q)'

alias dock='docker-compose'
alias dock-dev='docker-compose -f docker-compose.yaml -f docker-compose.development.yaml'
alias dock-ls='docker-machine ls'
alias dock-ssh='docker-machine ssh'
alias dock-scp='docker-machine scp'
alias dock-unuse='eval $(docker-machine env -u)'

function dock-use {
  eval $(docker-machine env $1)
}

function dock-stop {
    container=$1
    if [ -z "$container" ]
    then
        echo "Stopping all..."
        dock-dev down --remove-orphans
    else
        candidates=$(docker ps -q -f name=$container)
        if [ -n "$candidates" ]
        then
            docker stop $candidates
        else
            echo "No such container: $container"
	fi
    fi
}

Including a SERVICENAME in commands below tells Docker to apply commands only to that named service and its dependencies; omitting it will apply commands to all services in your compose file.

The docker-machine commands require that the remote Docker host was provisioned using docker-machine create. Still waiting for Docker to implement docker-machine export/import...

All Docker commands should be run from root of your project (same directory as your docker-compose.yaml file).

I want to...

Run my project locally (with build and watch tasks)

dock-dev up [SERVICENAME]

Quickly rebuild my app with code changes that were made outside of a watch task

dock-dev run --rm SERVICENAME bash

(run app build tasks; gulp, etc.)

exit (Ctrl-d)

Rebuild app dev image(s) after changing the package.json

dock-dev build --no-cache [SERVICENAME]

Stop running dev container(s) matching a NAME filter

dock-stop [CONTAINERNAME]

Rebuild prod image(s)

dock build --no-cache [SERVICENAME]

Bump app version and build a new prod image (with clean local git; see example package.json, etc. below)

npm version RELEASELEVEL
dock build SERVICENAME

Show which values Docker will use for docker-compose commands

dock config (prod containers)

dock-dev config (dev containers)

Provision a remote Docker host

See official Docker docs.

List remote docker-machine hosts

dock-ls

SSH to remote docker-machine host (the host OS--not a container!)

dock-ssh HOSTNAME

Deploy prod build(s) to remote host

dock-use HOSTNAME
dock up -d [SERVICENAME]
dock-unuse

Run arbitrary Docker command on remote host

dock-use HOSTNAME (connect to remote Docker host)

(your Docker command here)

dock-unuse (return to local Docker)

List running Docker containers

docker ps

List built images

docker images

Stop any running containers from this project

dock down

Remove all dangling containers, images and volumes

dclean

Example project structure and files

Basic directory structure for this example looks like:

my-app/
  dist/
  src/
  gulpfile.js
  package.json
  Dockerfile
  Dockerfile-development
docker-compose.yaml
docker-compose.development.yaml
.env

And some example files...

# docker-compose.yaml

version: '2'

services:
  myapp:
    build:
      context: ./my-app
    container_name: myapp
    environment:
      - NODE_ENV=production
      - AUTH_SECRET
      - AUTH_CALLBACK
    image: "myapp:${MY_APP_VERSION}"
    ports:
      - '5006:5000'
    restart: always

  mongodb:
    container_name: mongodb
    image: mongo:latest
    ports:
      - '27017:27017'
    volumes:
      - /data/db:/data/db
      - /data/backups:/data/backups
    restart: always

  redis:
    container_name: redis
    image: redis:latest
    ports:
      - '6379:6379'
    restart: always
# my-app/Dockerfile

FROM node:6.9.5

RUN useradd --user-group --create-home --shell /bin/false app

ENV HOME=/home/app

COPY . $HOME/my-app
RUN chown -R app:app $HOME/*

USER app
WORKDIR $HOME/my-app

RUN npm install --production --silent

CMD ["node", "dist/app.js"]
# docker-compose.development.yaml

version: '2'

services:
  myapp:
    build:
      context: ./my-app
      dockerfile: Dockerfile-development
    command: bash -c 'gulp clean build watch'
    environment:
      - NODE_ENV=development
      - AUTH_SECRET
      - AUTH_CALLBACK
    image: myapp-dev
    volumes:
      - ./my-app:/home/app/my-app
      - /home/app/my-app/node_modules
# my-app/Dockerfile-development

FROM node:6.9.5

RUN useradd --user-group --create-home --shell /bin/false app && \
  npm install --silent --global gulp-cli

ENV HOME=/home/app

COPY . $HOME/my-app
RUN chown -R app:app $HOME/*

USER app
WORKDIR $HOME/my-app

RUN npm install --silent
# my-app/package.json

{
  "name": "my-app",
  "version": "0.0.1",
  "main": "dist/app.js",
  "scripts": {
    "version": "docker-env-version ../.env"
  },
  "devDependencies": {
    "docker-env-version": "0.0.7",
    "gulp",
    ...
  },
  "dependencies": {
    ...
  }

Additional resources

You may find these Bash scripts make your Docker life easier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment