Managing services on one server with Portainer and Drone

AppVenture

Previously...

+ + shell scripts + git hooks

It was a mess.

  • No root access → Cannot install CentOS packages
  • cPanel was useless and intrusive, and costed us $20/mth!?
  • .htaccess RewriteRule proxy to Node.js apps
  • Git post-update → git clone REPO ~/build/npm installgruntjekyll build, all in the same user account hosting the files
  • ...

Goals

  • Host web services in many languages and with different databases
    • Node.js, PHP, generated HTML, Go
    • MariaDB, MongoDB, files
  • Constant updates should not impact existing services
  • Secure!
  • Avoid writing our own scripts/software
  • Easy to perform day-to-day operations

Solution: Docker!

(of course)

Docker...

  • provides a standardised environment.
  • isolates services and their dependencies from one another.
  • encourages modularisation.
  • enables migration between hosts.
  • is simple to adopt.
  • provides an additional layer of security.

Setup

Host OS: Container Linux

  • My favourite OS for containers!
  • Minimal, only has Docker
  • No package manager
  • Automatic updates!
  • Automatic updates like ChromeOS
    • Fetch updates using Google's Omaha
    • Writes updates to backup /usr partition
    • Sets that partition as default and reboot
  • Constant security and kernel updates

I configured it to perform updates between 11pm and 12am

Cloud Platform: DigitalOcean

  • Provides CoreOS as an OS option
  • We had experience with it
  • Easiest to get started

Sidenote: Cost us much less than our previous host.

Is a CLI enough?

Nah.

Portainer...

  • makes Docker really easy and fun to use.
  • has an experimental "recreate" button to stop, re-pull and start the image with the same settings.
    • Not the best solution, but it works well for us. We don't need an overly complex solution.

Kubernetes is awesome but not useful for this.

docker run --detach \
    --restart unless-stopped \
    --network management \
    --publish 9000:9000 \
    --volume /data/portainer:/data \
    --volume /var/run/docker.sock:/var/run/docker.sock \
    --name portainer \
    portainer

Success!

Success?

What about our private containers?

docker run --detach \
    --restart unless-stopped \
    --network management \
    --publish 5000:127.0.0.1:5001 \
    --volume /var/lib/registry:/data/registry \
    --name registry \
    registry:2

Benefits:

  • Use your own storage

Problems:

  • No authentication out of the box
  • You don't have unlimited storage per repository
  • Have to ensure it doesn't grow out of control in size

Quick recap...

What we have so far:

  • CoreOS as Docker Host
  • Manage containers with Portainer
  • Host containers on our own Docker Registry

What about source code?

Unlimited private repositories and users! Thanks, GitHub!

Are we done?

Continuous Delivery

  • For us, we need the automation so that one guy doesn't have to docker build and docker push
  • Also gives us a way to build Android APKs from source in a reproducable manner

Drone

Drone is a simple CI/CD platform written in Go. (I love Go)

  • Integrates with GitHub projects
  • Really easy to install
  • docker-compose-like syntax
  • Comes as a Docker container

Installing Drone is simple

  • On your Git host, register a new OAuth client and obtain secret
    • Drone supports GitHub, GitLab, Gitea, Gogs, Bitbucket, Coding
  • Run drone/drone:0.8, mount /var/lib/drone, set enviromental variables, publish ports 80
  • Run drone/agent:0.8, mount /var/run/docker.sock, set enviromental variables
  • Or, deploy with docker-compose

Check out http://docs.drone.io

Enable Drone on your project

  • Open the hamburger menu → Repositories and enable the project

Then, write a .drone.yml file.

cat ~/appventure-nush/caddy/.drone.yml

pipeline:
  test:
    image: 127.0.0.1:5001/caddy
    commands:
      - caddy -validate
  publish:
    image: plugins/docker     # Docker plugin builds 
                              #   and publishes images
    registry: registry:5000   # Not recommended
    insecure: true
    repo: registry:5000/caddy
    tags:
      - latest

cat ~/appventure-nush/some-android-app/.drone.yml

pipeline:
  build:
    image: 127.0.0.1:5001/builder-android
  release:
    image: plugins/github-release
    secrets: [ github_token ]
    files: app/build/outputs/apk/app-debug.apk
    when:
      event: tag

Caddy

Two networks:

  • primary, containing all the web services
  • management, containing the management services like portainer

Caddy reverse proxies services on the primary network, and terminates TLS using Let's Encrypt

Monitoring

Architecture

Thank you!