diff --git a/README.md b/README.md index 0d8ca9c..1d50b38 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,63 @@ -# dogvscat +# dogvscat (Work In Progress) -A Docker Swarm cluster needs more then just your app running. +This repo gives a few examples of patterns for how you might build Docker Swarm clusters with all the bells and whistles. -Sometimes live on [dogvs.cat](http://dogvs.cat) +A Docker Swarm cluster needs more then just your app running, it often needs at least these additional services: -COMING SOON (May/June 2018) +- Layer 7 Reverse Proxy (to host multiple HTTP sites on one port) +- Swarm-aware storage for data persistance +- Centralized logging of your app containers +- Centralized monitoring of nodes and containers +- Cluster management GUI +- Continuous deployment of updated images +This demo is meant for you to `git clone` and run locally to help you learn the tools and methods for building a complete Docker Swarm cluster. + +## Getting Started + +This repo holds two deployment examples for Docker Swarm + +- Docker Swarm CE (Community Edition) open source stack +- Docker Swarm EE (Enterprise Edition) stack + +The EE stack requires at least a trial license to deploy. + +## Deploying the Swarm CE Example + +You can do all this locally on a single node or optionally using Docker Machine to multi-node clusters. + +### Step 1: Set needed environment variables + +The scripts and compose/stack files use variables to make this demo easier to get started. Set these at your shell before running commands + +``` +TODO: add envs +``` + +### Step 2: (single node local Swarm) + +Just have Docker installed, either via Docker for Windows/Mac or on Linux. See my [YouTube videos on the proper way to setup your OS for Docker](https://www.youtube.com/watch?v=Fc7Rjll30jY&list=PL6cactdCCnTLqhFgmXAVdwLPCM_SZdGYq) using downloads from [store.docker.com](https://store.docker.com). + +Then just create a single-node Swarm in that engine: + +`docker swarm init` + +### Step 2: (multi-node docker-machine Swarm) + +`./create-servers.sh` gives example docker-machine commands for creating 3 nodes in various VM environments including locally with VirtualBox, Hyper-V, and in the cloud using Digital Ocean. + +### Step 3: Enable Docker Engine Metrics + +### Step 4: Initialize Swarm and Join Nodes + +### Step 5: Enable Persistent Storage with REX-Ray + +### Step 6: Deploy Reverse Proxy using Traefik + +### Step 7: Deploy Ops Tools: ELK, Prometheus, and Portainer + +### Step 8: Deploy sample apps and test + +## Deploying the Swarm EE Example + +TODO \ No newline at end of file diff --git a/create-servers.sh b/create-servers.sh index 5df958b..c79c4da 100755 --- a/create-servers.sh +++ b/create-servers.sh @@ -1,5 +1,5 @@ #!/bin/bash -set -x +# set -x # create managers servers in digital ocean with pre-set environment vars # https://docs.docker.com/machine/drivers/digital-ocean/ diff --git a/delete-servers.sh b/delete-servers.sh index e58b714..0012bc8 100755 --- a/delete-servers.sh +++ b/delete-servers.sh @@ -1,12 +1,13 @@ #!/bin/bash +set -x -# create managers servers +# delete all docker machines starting with dvc for server in {1..3}; do docker-machine rm -y dvc${server} & done -# create servers - +# delete all storage in DO (be sure you are ok deleting ALL storage in an account) +doctl compute volume ls --format ID --no-header | while read -r id; do doctl compute volume rm -f "$id"; done diff --git a/generate-some-votes.sh b/generate-some-votes.sh new file mode 100755 index 0000000..696e6eb --- /dev/null +++ b/generate-some-votes.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +# create POST data files with ab friendly formats +python make-data.py + +# create 3000 votes +ab -n 1000 -c 50 -p posta -T "application/x-www-form-urlencoded" http://vote.dogvs.cat/ +ab -n 1000 -c 50 -p postb -T "application/x-www-form-urlencoded" http://vote.dogvs.cat/ +ab -n 1000 -c 50 -p posta -T "application/x-www-form-urlencoded" http://vote.dogvs.cat/ diff --git a/hash-config-secret.sh b/hash-config-secret.sh index 16b2472..b5adb7f 100755 --- a/hash-config-secret.sh +++ b/hash-config-secret.sh @@ -1,3 +1,5 @@ #!/bin/sh +set -x + export LOGSTASH_CONF=$(shasum logstash.conf -a 512 | cut -c1-16) diff --git a/make-data.py b/make-data.py new file mode 100644 index 0000000..3aec8f5 --- /dev/null +++ b/make-data.py @@ -0,0 +1,13 @@ +# this creates urlencode-friendly files without EOL +import urllib +outfile = open('postb', 'w') +params = ({ 'vote': 'b' }) +encoded = urllib.urlencode(params) +outfile.write(encoded) +outfile.close() +outfile = open('posta', 'w') +params = ({ 'vote': 'a' }) +encoded = urllib.urlencode(params) +outfile.write(encoded) +outfile.close() + diff --git a/menu/index.html b/menu/index.html index c34d3fb..fa1a79c 100644 --- a/menu/index.html +++ b/menu/index.html @@ -21,7 +21,6 @@

Welcome to Dog vs. Cat

  • Dog vs. Cat GO VOTE!

  • Dog vs. Cat WATCH VOTE RESULTS

  • Ghost (blog with MySQL backend)

  • -
  • Swarm Visualizer

  • Portainer (Swarm GUI management)

  • Kibana (ELK log search)

  • Prometheus (monitoring console)

  • @@ -30,6 +29,7 @@

    Welcome to Dog vs. Cat

  • Unsee (monitoring alert dashbaord) (coming)

  • OpenFaaS (self-hosted functions) (coming)

  • Portus (self-hosted registry GUI) (coming)

  • +
  • GitLab CI/CD (coming)

  • Drone CI/CD (coming)

  • diff --git a/posta b/posta new file mode 100644 index 0000000..168c7ae --- /dev/null +++ b/posta @@ -0,0 +1 @@ +vote=a \ No newline at end of file diff --git a/postb b/postb new file mode 100644 index 0000000..e3792b3 --- /dev/null +++ b/postb @@ -0,0 +1 @@ +vote=b \ No newline at end of file diff --git a/stack-ee-ghost.yml b/stack-ee-ghost.yml index 79e3c11..464d41a 100644 --- a/stack-ee-ghost.yml +++ b/stack-ee-ghost.yml @@ -1,5 +1,72 @@ -version: '3.5' +version: '3.2' + +services: + + ghost: + image: ghost:1-alpine + networks: + - proxy + - ghost + environment: + # see https://docs.ghost.org/docs/config#section-running-ghost-with-config-env-variables + database__client: mysql + database__connection__host: db + database__connection__user: root + database__connection__password: OpdP2dy4jzAT + database__connection__database: ghost + url: http://ghost.dogvs.cat + deploy: + replicas: 1 + labels: + - traefik.port=2368 + - traefik.docker.network=proxy + - traefik.frontend.rule=Host:ghost.dogvs.cat + db: + image: mysql:5.7 + volumes: + - db:/var/lib/mysql + secrets: + - ghost-db-password + networks: + - ghost + deploy: + endpoint_mode: dnsrr + environment: + MYSQL_ROOT_PASSWORD_FILE: /run/secrets/ghost-db-password + + db-backup: + image: mysql:5.7 + command: sh -c "while true; do /usr/bin/mysqldump -u root --password=$$(< $$MYSQL_ROOT_PASSWORD_FILE) --all-databases --host=db > /backup/backup$$(date +'%H').sql ; sleep 3600; done" + volumes: + - db-backup:/backup + secrets: + - ghost-db-password + networks: + - ghost + environment: + MYSQL_ROOT_PASSWORD_FILE: /run/secrets/ghost-db-password + + #TODO: backup for static content + + +networks: + ghost: {} + proxy: + external: true volumes: db: - driver: cloudstor:aws + driver: cloudstor:latest + driver_opts: + size: 1 + db-backup: + driver: cloudstor:latest + driver_opts: + size: 1 + +secrets: + ghost-db-password: + external: true + + + diff --git a/stack-ghost.yml b/stack-ghost.yml index 5048712..db3d754 100644 --- a/stack-ghost.yml +++ b/stack-ghost.yml @@ -21,10 +21,10 @@ services: - traefik.port=2368 - traefik.docker.network=proxy - traefik.frontend.rule=Host:ghost.dogvs.cat - logging: - driver: "gelf" - options: - gelf-address: "udp://127.0.0.1:5000" + # logging: + # driver: "gelf" + # options: + # gelf-address: "udp://127.0.0.1:5000" db: image: mysql:5.7 @@ -38,11 +38,34 @@ services: endpoint_mode: dnsrr environment: MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db-password - logging: - driver: "gelf" - options: - gelf-address: "udp://127.0.0.1:5000" - + # logging: + # driver: "gelf" + # options: + # gelf-address: "udp://127.0.0.1:5000" + + + db-backup: + image: mysql:5.7 + command: sh -c "while true; do /usr/bin/mysqldump -u root --password=$$(< $$MYSQL_ROOT_PASSWORD_FILE) --all-databases --host=db > /backup/backup$$(date +'%H').sql ; sleep 3600; done" + volumes: + - db-backup:/backup + secrets: + - db-password + networks: + - ghost + environment: + MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db-password + deploy: + restart_policy: + delay: 600s + # logging: + # driver: "gelf" + # options: + # gelf-address: "udp://127.0.0.1:5000" + + #TODO: backup for static content + + networks: ghost: {} proxy: @@ -53,6 +76,10 @@ volumes: driver: rexray/dobs driver_opts: size: 1 + db-backup: + driver: rexray/dobs + driver_opts: + size: 1 secrets: db-password: diff --git a/stack-menu.yml b/stack-menu.yml index 3493466..6c72c80 100644 --- a/stack-menu.yml +++ b/stack-menu.yml @@ -12,10 +12,10 @@ services: - traefik.port=80 - traefik.docker.network=proxy - traefik.frontend.rule=Host:www.dogvs.cat,dogvs.cat - logging: - driver: "gelf" - options: - gelf-address: "udp://127.0.0.1:5000" + # logging: + # driver: "gelf" + # options: + # gelf-address: "udp://127.0.0.1:5000" networks: - proxy diff --git a/stack-prune.yml b/stack-prune.yml index 3eda93a..dede8e9 100644 --- a/stack-prune.yml +++ b/stack-prune.yml @@ -8,7 +8,7 @@ services: - /var/run/docker.sock:/var/run/docker.sock deploy: mode: global - logging: - driver: "gelf" - options: - gelf-address: "tcp://127.0.0.1:5000" + # logging: + # driver: "gelf" + # options: + # gelf-address: "tcp://127.0.0.1:5000" diff --git a/stack-swarm-exec.yml b/stack-rexray.yml similarity index 100% rename from stack-swarm-exec.yml rename to stack-rexray.yml diff --git a/stack-voting.yml b/stack-voting.yml index 08bd16d..8cb28da 100644 --- a/stack-voting.yml +++ b/stack-voting.yml @@ -11,10 +11,10 @@ services: - frontend deploy: endpoint_mode: dnsrr - logging: - driver: "gelf" - options: - gelf-address: "udp://127.0.0.1:5000" + # logging: + # driver: "gelf" + # options: + # gelf-address: "udp://127.0.0.1:5000" db: image: postgres:9.6 @@ -24,10 +24,10 @@ services: - backend deploy: endpoint_mode: dnsrr - logging: - driver: "gelf" - options: - gelf-address: "udp://127.0.0.1:5000" + # logging: + # driver: "gelf" + # options: + # gelf-address: "udp://127.0.0.1:5000" vote: image: bretfisher/examplevotingapp_vote @@ -40,10 +40,10 @@ services: - traefik.port=80 - traefik.docker.network=proxy - traefik.frontend.rule=Host:vote.dogvs.cat - logging: - driver: "gelf" - options: - gelf-address: "udp://127.0.0.1:5000" + # logging: + # driver: "gelf" + # options: + # gelf-address: "udp://127.0.0.1:5000" result: image: bretfisher/examplevotingapp_result @@ -55,10 +55,10 @@ services: - traefik.port=80 - traefik.docker.network=proxy - traefik.frontend.rule=Host:result.dogvs.cat - logging: - driver: "gelf" - options: - gelf-address: "udp://127.0.0.1:5000" + # logging: + # driver: "gelf" + # options: + # gelf-address: "udp://127.0.0.1:5000" worker: image: bretfisher/examplevotingapp_worker:java @@ -67,10 +67,10 @@ services: - backend deploy: replicas: 1 - logging: - driver: "gelf" - options: - gelf-address: "udp://127.0.0.1:5000" + # logging: + # driver: "gelf" + # options: + # gelf-address: "udp://127.0.0.1:5000" networks: frontend: {}