SlideShare a Scribd company logo
1 of 56
Download to read offline
Try This At HomeTry This At Home
Building a Personal Docker SwarmBuilding a Personal Docker Swarm
Matthew Clemente
@mjclemente
@mjclemente84
blog.mattclemente.com
@mjclemente
A Familiar StoryA Familiar Story
» Adobe ColdFusion 10 /11
» Windows Server 2008
» Microsoft IIS
» Rackspace
» FTP Deployments
» Dev Server (in basement)
Nyan Whale originally by Andrew Kennedy
Every ConferenceEvery Conference
Looking for DirectionLooking for Direction
Legacy
Infrastructure
Scriptable
Scalable
Containerized
12-Factor App
CI/CD
Microservices
Bret Fisher ResourcesBret Fisher Resources
»
»
»
»
»
»
»
»
»
BretFisher.com
Github AMA
Github Sample Swarm tools
Podcast
Docker Mastery
Docker Swarm Mastery
Docker Mastery for Node.js
Taking Docker to Production
Building Your Swarm Production Stack
Learned a LotLearned a Lot
Still don't know how to do this.
¯_(ツ)_/¯
You'll learn more onYou'll learn more on
the first day ofthe first day of
production than theproduction than the
previous two months.previous two months.
Bret Fisher, , DockerCon Europe 2017Taking Docker to Production
DoingDoing
isis
LearningLearning
All genuine learningAll genuine learning
comes throughcomes through
experience.experience.
John Dewey, Experience & Education, 1938
How do IHow do I
actuallyactually do do
this?this?
Don't tell me that it's possible without
showing me how!
GoalGoal
Learning By Doing
Concrete Examples
What This Talk Is Not:What This Talk Is Not:
» Intro to Docker
» Intro to Swarm
» Comprehensive
» "The Best Way"*
» Starting point
» Practical and concrete
» Code Samples!
» Necessarily limited
What This Talk Is:What This Talk Is:
Tooling and ServicesTooling and Services
» Structure my project?
» Minimize divergence between Dev and Prod?
» Use environment variables?
» Manage sensitive information?
» Use a private image registry?
» Tag images properly?
» Add Lucee extensions?
» Configure CI/CD for deployment?
» Monitor with FusionReactor?
» Handle sessions?
» File a tax extension?
How Do I...How Do I...
It can be doneIt can be done
_ಠ_ಠ
Begin with the endBegin with the end
in mind.in mind.
Stephen Covey, The 7 Habits of Highly Effective People, 1989
https://gitlab.com/mjclemente/api­mashup­cfml­swarm/ 
https://gitlab.com/mjclemente/starter­swarm­cfml 
Project StructureProject Structure
.
├── .env
├── .gitlab-ci.yml
├── .secrets
│   ├── cfml.admin.password.dev
│   └── cfml.admin.password.v1
├── app
│   ├── .CFConfig.json
│   ├── box.json
│   ├── server.json
│   └── wwwroot
│   └── index.cfm
├── build
│   ├── cfml
│   │   ├── Dockerfile
│   │   └── config
│   │   └── extensions
│   │   └── extension-loganalyzer-2.3.2.16.lex
│   └── deploy-secrets.sh
├── docker-compose.override.yml
├── docker-compose.prod.yml
└── docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
├── .env
├── .secrets
│   ├── cfml.admin.password.dev
│   └── cfml.admin.password.v1
.1
2
├── .gitlab-ci.yml3
4
5
6
├── app7
│   ├── .CFConfig.json8
│   ├── box.json9
│   ├── server.json10
│   └── wwwroot11
│   └── index.cfm12
├── build13
│   ├── cfml14
│   │   ├── Dockerfile15
│   │   └── config16
│   │   └── extensions17
│   │   └── extension-loganalyzer-2.3.2.16.lex18
│   └── deploy-secrets.sh19
├── docker-compose.override.yml20
├── docker-compose.prod.yml21
└── docker-compose.yml22
├── .gitlab-ci.yml
.1
├── .env2
3
├── .secrets4
│   ├── cfml.admin.password.dev5
│   └── cfml.admin.password.v16
├── app7
│   ├── .CFConfig.json8
│   ├── box.json9
│   ├── server.json10
│   └── wwwroot11
│   └── index.cfm12
├── build13
│   ├── cfml14
│   │   ├── Dockerfile15
│   │   └── config16
│   │   └── extensions17
│   │   └── extension-loganalyzer-2.3.2.16.lex18
│   └── deploy-secrets.sh19
├── docker-compose.override.yml20
├── docker-compose.prod.yml21
└── docker-compose.yml22
├── app
│   ├── .CFConfig.json
│   ├── box.json
│   ├── server.json
│   └── wwwroot
│   └── index.cfm
.1
├── .env2
├── .gitlab-ci.yml3
├── .secrets4
│   ├── cfml.admin.password.dev5
│   └── cfml.admin.password.v16
7
8
9
10
11
12
├── build13
│   ├── cfml14
│   │   ├── Dockerfile15
│   │   └── config16
│   │   └── extensions17
│   │   └── extension-loganalyzer-2.3.2.16.lex18
│   └── deploy-secrets.sh19
├── docker-compose.override.yml20
├── docker-compose.prod.yml21
└── docker-compose.yml22
├── build
│   ├── cfml
│   │   ├── Dockerfile
│   │   └── config
│   │   └── extensions
│   │   └── extension-loganalyzer-2.3.2.16.lex
│   └── deploy-secrets.sh
.1
├── .env2
├── .gitlab-ci.yml3
├── .secrets4
│   ├── cfml.admin.password.dev5
│   └── cfml.admin.password.v16
├── app7
│   ├── .CFConfig.json8
│   ├── box.json9
│   ├── server.json10
│   └── wwwroot11
│   └── index.cfm12
13
14
15
16
17
18
19
├── docker-compose.override.yml20
├── docker-compose.prod.yml21
└── docker-compose.yml22
├── docker-compose.override.yml
├── docker-compose.prod.yml
└── docker-compose.yml
.1
├── .env2
├── .gitlab-ci.yml3
├── .secrets4
│   ├── cfml.admin.password.dev5
│   └── cfml.admin.password.v16
├── app7
│   ├── .CFConfig.json8
│   ├── box.json9
│   ├── server.json10
│   └── wwwroot11
│   └── index.cfm12
├── build13
│   ├── cfml14
│   │   ├── Dockerfile15
│   │   └── config16
│   │   └── extensions17
│   │   └── extension-loganalyzer-2.3.2.16.lex18
│   └── deploy-secrets.sh19
20
21
22
https://gitlab.com/mjclemente/starter­swarm­cfml
Sharing ConfigurationSharing Configuration
.
├── docker-compose.override.yml
├── docker-compose.prod.yml
└── docker-compose.yml
1
2
3
4
├── docker-compose.override.yml
└── docker-compose.yml
.1
2
├── docker-compose.prod.yml3
4
├── docker-compose.prod.yml
└── docker-compose.yml
.1
├── docker-compose.override.yml2
3
4
 Understanding Multiple Compose Files
Bret Fisher AMA on docker­compose.override.yml
$ docker-compose up
Minimize Divergence Between Dev and ProdMinimize Divergence Between Dev and Prod
Sharing ConfigurationSharing Configuration
$ docker-compose 
-f docker-compose.yml 
-f docker-compose.prod.yml 
up
# Works if not dependent on Swarm features
1
2
3
4
5
-f docker-compose.prod.yml 
$ docker-compose 1
-f docker-compose.yml 2
3
up4
# Works if not dependent on Swarm features5
-f docker-compose.yml 
$ docker-compose 1
2
-f docker-compose.prod.yml 3
up4
# Works if not dependent on Swarm features5
-f docker-compose.yml 
-f docker-compose.prod.yml 
$ docker-compose 1
2
3
up4
# Works if not dependent on Swarm features5
$ docker-compose 
-f docker-compose.yml 
-f docker-compose.prod.yml 
up
# Works if not dependent on Swarm features
1
2
3
4
5
docker stack deploy 
-c docker-compose.yml 
-c docker-compose.prod.yml 
test
# For Swarm deployments
1
2
3
4
5
-c docker-compose.prod.yml 
docker stack deploy 1
-c docker-compose.yml 2
3
test4
# For Swarm deployments5
-c docker-compose.yml 
docker stack deploy 1
2
-c docker-compose.prod.yml 3
test4
# For Swarm deployments5
-c docker-compose.yml 
-c docker-compose.prod.yml 
docker stack deploy 1
2
3
test4
# For Swarm deployments5
docker stack deploy 
-c docker-compose.yml 
-c docker-compose.prod.yml 
test
# For Swarm deployments
1
2
3
4
5
Minimize Divergence Between Dev and ProdMinimize Divergence Between Dev and Prod
version: "3.7"
services:
cfml:
image: "registry.gitlab.com/${CI_PROJE
build:
context: .
dockerfile: ./build/cfml/Dockerfile
environment:
PORT: 8080
SSL_PORT: 8443
cfconfigfile: .CFConfig.json
cfconfig_inspectTemplate: never
secrets:
- source: cfml.admin.password
target: cfml.admin.password
ports:
- target: 8080
published: 80
- target: 8443
published: 443
networks:
internal:
driver: overlay
secrets:
cfml.admin.password:
external: true
name: cfml.admin.password.v1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
cfconfig_inspectTemplate: never
version: "3.7"1
2
services:3
cfml:4
image: "registry.gitlab.com/${CI_PROJE5
build:6
context: .7
dockerfile: ./build/cfml/Dockerfile8
environment:9
PORT: 808010
SSL_PORT: 844311
cfconfigfile: .CFConfig.json12
13
secrets:14
- source: cfml.admin.password15
target: cfml.admin.password16
ports:17
- target: 808018
published: 8019
- target: 844320
published: 44321
22
networks:23
internal:24
driver: overlay25
26
secrets:27
cfml.admin.password:28
external: true29
name: cfml.admin.password.v130
networks:
internal:
driver: overlay
version: "3.7"1
2
services:3
cfml:4
image: "registry.gitlab.com/${CI_PROJE5
build:6
context: .7
dockerfile: ./build/cfml/Dockerfile8
environment:9
PORT: 808010
SSL_PORT: 844311
cfconfigfile: .CFConfig.json12
cfconfig_inspectTemplate: never13
secrets:14
- source: cfml.admin.password15
target: cfml.admin.password16
ports:17
- target: 808018
published: 8019
- target: 844320
published: 44321
22
23
24
25
26
secrets:27
cfml.admin.password:28
external: true29
name: cfml.admin.password.v130
secrets:
cfml.admin.password:
external: true
name: cfml.admin.password.v1
version: "3.7"1
2
services:3
cfml:4
image: "registry.gitlab.com/${CI_PROJE5
build:6
context: .7
dockerfile: ./build/cfml/Dockerfile8
environment:9
PORT: 808010
SSL_PORT: 844311
cfconfigfile: .CFConfig.json12
cfconfig_inspectTemplate: never13
secrets:14
- source: cfml.admin.password15
target: cfml.admin.password16
ports:17
- target: 808018
published: 8019
- target: 844320
published: 44321
22
networks:23
internal:24
driver: overlay25
26
27
28
29
30
version: "3.7"
services:
cfml:
volumes:
- ./app:/app
environment:
cfconfig_inspectTemplate: always
ports:
- target: 8080
published: 8080
- target: 8443
published: 8443
networks:
internal:
driver: bridge
secrets:
cfml.admin.password:
external: false
file: ./.secrets/cfml.admin.password.dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
cfconfig_inspectTemplate: always
version: "3.7"1
2
services:3
cfml:4
volumes:5
- ./app:/app6
environment:7
8
ports:9
- target: 808010
published: 808011
- target: 844312
published: 844313
14
networks:15
internal:16
driver: bridge17
18
secrets:19
cfml.admin.password:20
external: false21
file: ./.secrets/cfml.admin.password.dev22
networks:
internal:
driver: bridge
version: "3.7"1
2
services:3
cfml:4
volumes:5
- ./app:/app6
environment:7
cfconfig_inspectTemplate: always8
ports:9
- target: 808010
published: 808011
- target: 844312
published: 844313
14
15
16
17
18
secrets:19
cfml.admin.password:20
external: false21
file: ./.secrets/cfml.admin.password.dev22
secrets:
cfml.admin.password:
external: false
file: ./.secrets/cfml.admin.password.dev
version: "3.7"1
2
services:3
cfml:4
volumes:5
- ./app:/app6
environment:7
cfconfig_inspectTemplate: always8
ports:9
- target: 808010
published: 808011
- target: 844312
published: 844313
14
networks:15
internal:16
driver: bridge17
18
19
20
21
22
docker­compose.override.ymldocker­compose.yml
the last slidethe last slide
was awas a lielie
The real worldThe real world
doesn't look likedoesn't look like
demos.demos.
┻━┻︵(°□°)/ ︵┻━┻
Swarm CreationSwarm Creation
https://github.com/mjclemente/do­swarm­create
Swarm CreationSwarm Creation
doctl
# Create Docker Droplet
doctl compute droplet create test
--size 1gb
--image docker-18-04
--region nyc1
# List Droplets
doctl compute droplet list
#Delete a Droplet
doctl compute droplet delete 123456
#List SSH Key Ids and Names
doctl compute droplet list --format "ID,Name"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(Official DigitalOcean Command­Line Client)
Swarm CreationSwarm Creation
Swarm Creation Script for DigitalOcean
Swarm InitializedSwarm Initialized
https://12factor.net/config
https://github.com/Ortus­Solutions/docker­commandbox#environment­variables
https://docs.docker.com/compose/environment­variables/
Environment VariablesEnvironment Variables
» Environment for configuration
» Modular and easy to change
» Managed in .env file
.env
CI_PROJECT_NAMESPACE=mjclemente
OTHER_SETTING=
FOO=bar
1
2
3
https://direnv.net/
${Env} in Compose${Env} in Compose
image:
"registry.gitlab.com/${CI_PROJECT_NAMESPACE}/starter-swarm-
cfml/cfml:${BUILD_TAG:-latest}"
version: "3.7"1
2
services:3
cfml:4
5
build:6
context: .7
dockerfile: ./build/cfml/Dockerfile8
environment:9
PORT: 808010
SSL_PORT: 844311
cfconfigfile: .CFConfig.json12
cfconfig_inspectTemplate: never13
CF_ADMINPASSWORD: <<SECRET:cfml.admin.password>>14
secrets:15
- source: cfml.admin.password16
target: cfml.admin.password17
environment:
PORT: 8080
SSL_PORT: 8443
cfconfigfile: .CFConfig.json
cfconfig_inspectTemplate: never
CF_ADMINPASSWORD: <<SECRET:cfml.admin.password>>
version: "3.7"1
2
services:3
cfml:4
image:
"registry.gitlab.com/${CI_PROJECT_NAMESPACE}/starter-swarm-
cfml/cfml:${BUILD_TAG:-latest}"
5
build:6
context: .7
dockerfile: ./build/cfml/Dockerfile8
9
10
11
12
13
14
secrets:15
- source: cfml.admin.password16
target: cfml.admin.password17
${Env} in CFConfig.json${Env} in CFConfig.json
"adminPassword":"${CF_ADMINPASSWORD}",
{1
2
"applicationListener":"modern",3
"applicationMode":"curr2root",4
"applicationTimeout":"1,0,0,0",5
"cacheDefaultFile":"",6
"cacheDefaultFunction":"",7
"cacheDefaultHTTP":"",8
"cacheDefaultInclude":"",9
"cacheDefaultObject":"object",10
"cacheDefaultQuery":"",11
"cacheDefaultResource":"",12
"cacheDefaultTemplate":"",13
"cacheDefaultWebservice":"",14
"caches":{},15
"CGIReadOnly":"true",16
"clientCookies":"true",17
(Same behavior in server.json)
Env variables prone to leakEnv variables prone to leak
Docker Swarm SecretsDocker Swarm Secrets
» Immutable by design
» Account for rotation
» Account for Dev and Production
» Team conventions are essential
https://docs.docker.com/engine/swarm/secrets/
https://docs.docker.com/compose/compose­file/#secrets
secrets:
cfml.admin.password:
external: true
name: cfml.admin.password.v1
secrets:
cfml.admin.password:
external: false
file: ./.secrets/cfml.admin.password.dev
docker­compose.override.ymldocker­compose.yml
version: "3.7"
services:
cfml:
...
environment:
PORT: 8080
SSL_PORT: 8443
cfconfigfile: .CFConfig.json
cfconfig_inspectTemplate: never
CF_ADMINPASSWORD: <<SECRET:cfml.admin.password>>
secrets:
- source: cfml.admin.password
target: cfml.admin.password
( ••)( ••)
( ••)>⌐■-■( ••)>⌐■-■
(⌐■_■) #Secrets!(⌐■_■) #Secrets!
https://gitlab.com/mjclemente/starter­swarm­cfml/blob/master/build/deploy­secrets.sh
CI/CD with Gitlab RunnersCI/CD with Gitlab Runners
» Configured via .gitlab-ci.yml
» Run automagically
» Multiple types of runners
» Use a dedicated SSH Key
https://docs.gitlab.com/ee/ci/quick_start/
https://gitlab.com/mjclemente/starter­swarm­cfml/blob/master/.gitlab­ci.yml
₍₍ ᕕ( ಠ‿ಠ)ᕗ
.gitlab­ci.yml
» File containing all definitions of how
your project should be built
https://docs.gitlab.com/ee/ci/yaml/
before_script:
before_script:
## We're gonna log into the gitlab registry, as that's where
these images are stored
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN
registry.gitlab.com
## Git needed to get the date from the commit sha
- apk add git
## So we can see what's going on in the logs
- docker info
## setup environment variables
- [configuration continues]
1
2
3
4
5
6
7
8
9
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN
registry.gitlab.com
before_script:1
## We're gonna log into the gitlab registry, as that's where
these images are stored
2
3
## Git needed to get the date from the commit sha4
- apk add git5
## So we can see what's going on in the logs6
- docker info7
## setup environment variables8
- [configuration continues]9
- apk add git
before_script:1
## We're gonna log into the gitlab registry, as that's where
these images are stored
2
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN
registry.gitlab.com
3
## Git needed to get the date from the commit sha4
5
## So we can see what's going on in the logs6
- docker info7
## setup environment variables8
- [configuration continues]9
before_script:
## We're gonna log into the gitlab registry, as that's where
these images are stored
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN
registry.gitlab.com
## Git needed to get the date from the commit sha
- apk add git
## So we can see what's going on in the logs
- docker info
## setup environment variables
- [configuration continues]
1
2
3
4
5
6
7
8
9
Getting everything set up
.gitlab­ci.yml
https://docs.gitlab.com/ee/ci/yaml/#before_script­and­after_script
Tagging Custom ImagesTagging Custom Images
» Don't just use "latest"
» Combination of date and commit
before_script:
- export COMMIT_TIME=$(git show -s --format=%ci $CI_COMMIT_SHA)
- export COMMIT_TIME_SHORT=$(echo $COMMIT_TIME | head -c10)
- export BUILD_TAG="${COMMIT_TIME_SHORT}_$CI_COMMIT_SHORT_SHA"
1
- [earlier configuration]2
## Use git `show` with --format=%ci to get ISO 8601 date3
4
## Use first 10 characters of the datetime (ie: 2019-03-19)5
6
7
- export COMMIT_TIME=$(git show -s --format=%ci $CI_COMMIT_SHA)
before_script:1
- [earlier configuration]2
## Use git `show` with --format=%ci to get ISO 8601 date3
4
## Use first 10 characters of the datetime (ie: 2019-03-19)5
- export COMMIT_TIME_SHORT=$(echo $COMMIT_TIME | head -c10)6
- export BUILD_TAG="${COMMIT_TIME_SHORT}_$CI_COMMIT_SHORT_SHA"7
- export COMMIT_TIME_SHORT=$(echo $COMMIT_TIME | head -c10)
before_script:1
- [earlier configuration]2
## Use git `show` with --format=%ci to get ISO 8601 date3
- export COMMIT_TIME=$(git show -s --format=%ci $CI_COMMIT_SHA)4
## Use first 10 characters of the datetime (ie: 2019-03-19)5
6
- export BUILD_TAG="${COMMIT_TIME_SHORT}_$CI_COMMIT_SHORT_SHA"7 - export BUILD_TAG="${COMMIT_TIME_SHORT}_$CI_COMMIT_SHORT_SHA"
before_script:1
- [earlier configuration]2
## Use git `show` with --format=%ci to get ISO 8601 date3
- export COMMIT_TIME=$(git show -s --format=%ci $CI_COMMIT_SHA)4
## Use first 10 characters of the datetime (ie: 2019-03-19)5
- export COMMIT_TIME_SHORT=$(echo $COMMIT_TIME | head -c10)6
7
.gitlab­ci.yml
Control Pipeline StagesControl Pipeline Stages
deploy:
stage: deploy
only:
- deploy
except:
variables:
- $CI_COMMIT_MESSAGE =~ /Initial commit/i
- $CI_COMMIT_MESSAGE =~ /skip deploy/i
- $CI_COMMIT_MESSAGE =~ /don't deploy/i
https://docs.gitlab.com/ee/ci/yaml/#onlyexcept­basic
.gitlab­ci.yml
Building Custom ImagesBuilding Custom Images
build:
stage: build
only:
- deploy
script:
## Build the image, with the build tag and the latest tag
- docker build --tag $CONTAINER_IMAGE:$BUILD_TAG --tag
$CONTAINER_IMAGE:latest -f ./build/cfml/Dockerfile .
## List images, so we can confirm success
- docker image ls
## Push with the build tag
- docker push $CONTAINER_IMAGE:$BUILD_TAG
## Push with latest
- docker push $CONTAINER_IMAGE:latest
.gitlab­ci.yml
Stack DeploymentStack Deployment
Stack DeploymentStack Deployment
deploy:
stage: deploy
script:
- [a lot of SSH related config]
## Enable SSH functionality made possible in 18.0.9 to switch
our context to the remote server
- export DOCKER_HOST=ssh://root@${HOST_IP}
## Deploy the stack - registry auth is for gitlab
- docker stack deploy -c docker-compose.yml -c docker-
compose.prod.yml basetest --with-registry-auth
.gitlab­ci.yml
» Swarm's missing UI
» Configuration and management
» Separate from application stack
PortainerPortainer
»
»
»
Hybrid license
Easy installation (ForgeBox)
Some manual configuration
FusionReactor (Cloud)FusionReactor (Cloud)
» Required in multi-node Swarms
» Free options
» Provided via (beta) Lucee Extensions
» Paid options are superior
Sessions and CachingSessions and Caching
https://blog.mattclemente.com/2018/08/17/install­lucee­extensions­on­commandbox­docker­containers.html
SSLSSL
https://blog.filippo.io/mkcert­valid­https­certificates­for­localhost/
https://letsencrypt.org/docs/certificates­for­localhost/
mkcert
(Zero­config tool to make locally trusted development certificates)
+
All things areAll things are
difficult before theydifficult before they
are easy.are easy.
Dr. Thomas Fuller, Gnomologia, 1732
Try This At HomeTry This At Home
Building a Personal Docker SwarmBuilding a Personal Docker Swarm
Matthew Clemente
@mjclemente
@mjclemente84
blog.mattclemente.com
@mjclemente

More Related Content

What's hot

Developing and Deploying PHP with Docker
Developing and Deploying PHP with DockerDeveloping and Deploying PHP with Docker
Developing and Deploying PHP with Docker
Patrick Mizer
 

What's hot (20)

Jenkins multibranch pipeline workshop sep 2018
Jenkins multibranch pipeline workshop sep 2018Jenkins multibranch pipeline workshop sep 2018
Jenkins multibranch pipeline workshop sep 2018
 
DCSF 19 Deploying Rootless buildkit on Kubernetes
DCSF 19 Deploying Rootless buildkit on KubernetesDCSF 19 Deploying Rootless buildkit on Kubernetes
DCSF 19 Deploying Rootless buildkit on Kubernetes
 
Running Docker in Development & Production (DevSum 2015)
Running Docker in Development & Production (DevSum 2015)Running Docker in Development & Production (DevSum 2015)
Running Docker in Development & Production (DevSum 2015)
 
Scaling your jenkins master with docker
Scaling your jenkins master with dockerScaling your jenkins master with docker
Scaling your jenkins master with docker
 
Drone CI/CD Platform
Drone CI/CD PlatformDrone CI/CD Platform
Drone CI/CD Platform
 
Real World Experience of Running Docker in Development and Production
Real World Experience of Running Docker in Development and ProductionReal World Experience of Running Docker in Development and Production
Real World Experience of Running Docker in Development and Production
 
DCSF19 Dockerfile Best Practices
DCSF19 Dockerfile Best PracticesDCSF19 Dockerfile Best Practices
DCSF19 Dockerfile Best Practices
 
Docker 初探,實驗室中的運貨鯨
Docker 初探,實驗室中的運貨鯨Docker 初探,實驗室中的運貨鯨
Docker 初探,實驗室中的運貨鯨
 
DCEU 18: Dockerfile Best Practices
DCEU 18: Dockerfile Best PracticesDCEU 18: Dockerfile Best Practices
DCEU 18: Dockerfile Best Practices
 
Docker workshop 0507 Taichung
Docker workshop 0507 Taichung Docker workshop 0507 Taichung
Docker workshop 0507 Taichung
 
當專案漸趕,當遷移也不再那麼難 (Ship Your Projects with Docker EcoSystem)
當專案漸趕,當遷移也不再那麼難 (Ship Your Projects with Docker EcoSystem)當專案漸趕,當遷移也不再那麼難 (Ship Your Projects with Docker EcoSystem)
當專案漸趕,當遷移也不再那麼難 (Ship Your Projects with Docker EcoSystem)
 
Continuous Delivery Workshop with Ansible x GitLab CI (2nd+)
Continuous Delivery Workshop with Ansible x GitLab CI (2nd+)Continuous Delivery Workshop with Ansible x GitLab CI (2nd+)
Continuous Delivery Workshop with Ansible x GitLab CI (2nd+)
 
Docker summit 2015: 以 Docker Swarm 打造多主機叢集環境
Docker summit 2015: 以 Docker Swarm 打造多主機叢集環境Docker summit 2015: 以 Docker Swarm 打造多主機叢集環境
Docker summit 2015: 以 Docker Swarm 打造多主機叢集環境
 
Drone CI/CD 自動化測試及部署
Drone CI/CD 自動化測試及部署Drone CI/CD 自動化測試及部署
Drone CI/CD 自動化測試及部署
 
Kubernetes + Python = ❤ - Cloud Native Prague
Kubernetes + Python = ❤ - Cloud Native PragueKubernetes + Python = ❤ - Cloud Native Prague
Kubernetes + Python = ❤ - Cloud Native Prague
 
Developing and Deploying PHP with Docker
Developing and Deploying PHP with DockerDeveloping and Deploying PHP with Docker
Developing and Deploying PHP with Docker
 
Enabling Microservices @Orbitz - DockerCon 2015
Enabling Microservices @Orbitz - DockerCon 2015Enabling Microservices @Orbitz - DockerCon 2015
Enabling Microservices @Orbitz - DockerCon 2015
 
Docker in Production: Reality, Not Hype
Docker in Production: Reality, Not HypeDocker in Production: Reality, Not Hype
Docker in Production: Reality, Not Hype
 
Using Docker in the Real World
Using Docker in the Real WorldUsing Docker in the Real World
Using Docker in the Real World
 
Continuous delivery with docker
Continuous delivery with dockerContinuous delivery with docker
Continuous delivery with docker
 

Similar to ITB2019 Try This At Home: Building a Personal Docker Swarm - Matt Clemente

Dockerizing Symfony Applications - Symfony Live Berlin 2014
Dockerizing Symfony Applications - Symfony Live Berlin 2014Dockerizing Symfony Applications - Symfony Live Berlin 2014
Dockerizing Symfony Applications - Symfony Live Berlin 2014
D
 

Similar to ITB2019 Try This At Home: Building a Personal Docker Swarm - Matt Clemente (20)

廣宣學堂: 容器進階實務 - Docker進深研究班
廣宣學堂: 容器進階實務 - Docker進深研究班廣宣學堂: 容器進階實務 - Docker進深研究班
廣宣學堂: 容器進階實務 - Docker進深研究班
 
Docker 進階實務班
Docker 進階實務班Docker 進階實務班
Docker 進階實務班
 
DCEU 18: Developing with Docker Containers
DCEU 18: Developing with Docker ContainersDCEU 18: Developing with Docker Containers
DCEU 18: Developing with Docker Containers
 
Docker for Web Developers: A Sneak Peek
Docker for Web Developers: A Sneak PeekDocker for Web Developers: A Sneak Peek
Docker for Web Developers: A Sneak Peek
 
Docker Security workshop slides
Docker Security workshop slidesDocker Security workshop slides
Docker Security workshop slides
 
桃園市教育局Docker技術入門與實作
桃園市教育局Docker技術入門與實作桃園市教育局Docker技術入門與實作
桃園市教育局Docker技術入門與實作
 
Docker Basics & Alfresco Content Services
Docker Basics & Alfresco Content ServicesDocker Basics & Alfresco Content Services
Docker Basics & Alfresco Content Services
 
Docker linuxday 2015
Docker linuxday 2015Docker linuxday 2015
Docker linuxday 2015
 
PuppetConf 2016: The Challenges with Container Configuration – David Lutterko...
PuppetConf 2016: The Challenges with Container Configuration – David Lutterko...PuppetConf 2016: The Challenges with Container Configuration – David Lutterko...
PuppetConf 2016: The Challenges with Container Configuration – David Lutterko...
 
Challenges of container configuration
Challenges of container configurationChallenges of container configuration
Challenges of container configuration
 
Clustering Docker with Docker Swarm on openSUSE
Clustering Docker with Docker Swarm on openSUSEClustering Docker with Docker Swarm on openSUSE
Clustering Docker with Docker Swarm on openSUSE
 
Perspectives on Docker
Perspectives on DockerPerspectives on Docker
Perspectives on Docker
 
Real-World Docker: 10 Things We've Learned
Real-World Docker: 10 Things We've Learned  Real-World Docker: 10 Things We've Learned
Real-World Docker: 10 Things We've Learned
 
Digital Forensics and Incident Response in The Cloud Part 3
Digital Forensics and Incident Response in The Cloud Part 3Digital Forensics and Incident Response in The Cloud Part 3
Digital Forensics and Incident Response in The Cloud Part 3
 
Academy PRO: Docker. Part 4
Academy PRO: Docker. Part 4Academy PRO: Docker. Part 4
Academy PRO: Docker. Part 4
 
Deploying Windows Containers on Windows Server 2016
Deploying Windows Containers on Windows Server 2016Deploying Windows Containers on Windows Server 2016
Deploying Windows Containers on Windows Server 2016
 
DCSF 19 Building Your Development Pipeline
DCSF 19 Building Your Development Pipeline  DCSF 19 Building Your Development Pipeline
DCSF 19 Building Your Development Pipeline
 
Dockerizing Symfony Applications - Symfony Live Berlin 2014
Dockerizing Symfony Applications - Symfony Live Berlin 2014Dockerizing Symfony Applications - Symfony Live Berlin 2014
Dockerizing Symfony Applications - Symfony Live Berlin 2014
 
Docker for mere mortals
Docker for mere mortalsDocker for mere mortals
Docker for mere mortals
 
時代在變 Docker 要會:台北 Docker 一日入門篇
時代在變 Docker 要會:台北 Docker 一日入門篇時代在變 Docker 要會:台北 Docker 一日入門篇
時代在變 Docker 要會:台北 Docker 一日入門篇
 

More from Ortus Solutions, Corp

More from Ortus Solutions, Corp (20)

BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
Ortus Government.pdf
Ortus Government.pdfOrtus Government.pdf
Ortus Government.pdf
 
Luis Majano The Battlefield ORM
Luis Majano The Battlefield ORMLuis Majano The Battlefield ORM
Luis Majano The Battlefield ORM
 
Brad Wood - CommandBox CLI
Brad Wood - CommandBox CLI Brad Wood - CommandBox CLI
Brad Wood - CommandBox CLI
 
Secure your Secrets and Settings in ColdFusion
Secure your Secrets and Settings in ColdFusionSecure your Secrets and Settings in ColdFusion
Secure your Secrets and Settings in ColdFusion
 
Daniel Garcia ContentBox: CFSummit 2023
Daniel Garcia ContentBox: CFSummit 2023Daniel Garcia ContentBox: CFSummit 2023
Daniel Garcia ContentBox: CFSummit 2023
 
ITB_2023_Human-Friendly_Scheduled_Tasks_Giancarlo_Gomez.pdf
ITB_2023_Human-Friendly_Scheduled_Tasks_Giancarlo_Gomez.pdfITB_2023_Human-Friendly_Scheduled_Tasks_Giancarlo_Gomez.pdf
ITB_2023_Human-Friendly_Scheduled_Tasks_Giancarlo_Gomez.pdf
 
ITB_2023_CommandBox_Multi-Server_-_Brad_Wood.pdf
ITB_2023_CommandBox_Multi-Server_-_Brad_Wood.pdfITB_2023_CommandBox_Multi-Server_-_Brad_Wood.pdf
ITB_2023_CommandBox_Multi-Server_-_Brad_Wood.pdf
 
ITB_2023_The_Many_Layers_of_OAuth_Keith_Casey_.pdf
ITB_2023_The_Many_Layers_of_OAuth_Keith_Casey_.pdfITB_2023_The_Many_Layers_of_OAuth_Keith_Casey_.pdf
ITB_2023_The_Many_Layers_of_OAuth_Keith_Casey_.pdf
 
ITB_2023_Relationships_are_Hard_Data_modeling_with_NoSQL_Curt_Gratz.pdf
ITB_2023_Relationships_are_Hard_Data_modeling_with_NoSQL_Curt_Gratz.pdfITB_2023_Relationships_are_Hard_Data_modeling_with_NoSQL_Curt_Gratz.pdf
ITB_2023_Relationships_are_Hard_Data_modeling_with_NoSQL_Curt_Gratz.pdf
 
ITB_2023_Extend_your_contentbox_apps_with_custom_modules_Javier_Quintero.pdf
ITB_2023_Extend_your_contentbox_apps_with_custom_modules_Javier_Quintero.pdfITB_2023_Extend_your_contentbox_apps_with_custom_modules_Javier_Quintero.pdf
ITB_2023_Extend_your_contentbox_apps_with_custom_modules_Javier_Quintero.pdf
 
ITB_2023_25_Most_Dangerous_Software_Weaknesses_Pete_Freitag.pdf
ITB_2023_25_Most_Dangerous_Software_Weaknesses_Pete_Freitag.pdfITB_2023_25_Most_Dangerous_Software_Weaknesses_Pete_Freitag.pdf
ITB_2023_25_Most_Dangerous_Software_Weaknesses_Pete_Freitag.pdf
 
ITB_2023_CBWire_v3_Grant_Copley.pdf
ITB_2023_CBWire_v3_Grant_Copley.pdfITB_2023_CBWire_v3_Grant_Copley.pdf
ITB_2023_CBWire_v3_Grant_Copley.pdf
 
ITB_2023_Practical_AI_with_OpenAI_-_Grant_Copley_.pdf
ITB_2023_Practical_AI_with_OpenAI_-_Grant_Copley_.pdfITB_2023_Practical_AI_with_OpenAI_-_Grant_Copley_.pdf
ITB_2023_Practical_AI_with_OpenAI_-_Grant_Copley_.pdf
 
ITB_2023_When_Your_Applications_Work_As_a_Team_Nathaniel_Francis.pdf
ITB_2023_When_Your_Applications_Work_As_a_Team_Nathaniel_Francis.pdfITB_2023_When_Your_Applications_Work_As_a_Team_Nathaniel_Francis.pdf
ITB_2023_When_Your_Applications_Work_As_a_Team_Nathaniel_Francis.pdf
 
ITB_2023_Faster_Apps_That_Wont_Get_Crushed_Brian_Klaas.pdf
ITB_2023_Faster_Apps_That_Wont_Get_Crushed_Brian_Klaas.pdfITB_2023_Faster_Apps_That_Wont_Get_Crushed_Brian_Klaas.pdf
ITB_2023_Faster_Apps_That_Wont_Get_Crushed_Brian_Klaas.pdf
 
ITB_2023_Chatgpt_Box_Scott_Steinbeck.pdf
ITB_2023_Chatgpt_Box_Scott_Steinbeck.pdfITB_2023_Chatgpt_Box_Scott_Steinbeck.pdf
ITB_2023_Chatgpt_Box_Scott_Steinbeck.pdf
 
ITB_2023_CommandBox_Task_Runners_Brad_Wood.pdf
ITB_2023_CommandBox_Task_Runners_Brad_Wood.pdfITB_2023_CommandBox_Task_Runners_Brad_Wood.pdf
ITB_2023_CommandBox_Task_Runners_Brad_Wood.pdf
 
ITB_2023_Create_as_many_web_sites_or_web_apps_as_you_want_George_Murphy.pdf
ITB_2023_Create_as_many_web_sites_or_web_apps_as_you_want_George_Murphy.pdfITB_2023_Create_as_many_web_sites_or_web_apps_as_you_want_George_Murphy.pdf
ITB_2023_Create_as_many_web_sites_or_web_apps_as_you_want_George_Murphy.pdf
 
ITB2023 Developing for Performance - Denard Springle.pdf
ITB2023 Developing for Performance - Denard Springle.pdfITB2023 Developing for Performance - Denard Springle.pdf
ITB2023 Developing for Performance - Denard Springle.pdf
 

Recently uploaded

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 

Recently uploaded (20)

Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024
 

ITB2019 Try This At Home: Building a Personal Docker Swarm - Matt Clemente

  • 1. Try This At HomeTry This At Home Building a Personal Docker SwarmBuilding a Personal Docker Swarm Matthew Clemente @mjclemente @mjclemente84 blog.mattclemente.com @mjclemente
  • 2. A Familiar StoryA Familiar Story » Adobe ColdFusion 10 /11 » Windows Server 2008 » Microsoft IIS » Rackspace » FTP Deployments » Dev Server (in basement)
  • 4. Looking for DirectionLooking for Direction Legacy Infrastructure Scriptable Scalable Containerized 12-Factor App CI/CD Microservices
  • 5. Bret Fisher ResourcesBret Fisher Resources » » » » » » » » » BretFisher.com Github AMA Github Sample Swarm tools Podcast Docker Mastery Docker Swarm Mastery Docker Mastery for Node.js Taking Docker to Production Building Your Swarm Production Stack
  • 6. Learned a LotLearned a Lot Still don't know how to do this. ¯_(ツ)_/¯
  • 7. You'll learn more onYou'll learn more on the first day ofthe first day of production than theproduction than the previous two months.previous two months. Bret Fisher, , DockerCon Europe 2017Taking Docker to Production
  • 9. All genuine learningAll genuine learning comes throughcomes through experience.experience. John Dewey, Experience & Education, 1938
  • 10. How do IHow do I actuallyactually do do this?this? Don't tell me that it's possible without showing me how!
  • 11.
  • 12.
  • 14. What This Talk Is Not:What This Talk Is Not: » Intro to Docker » Intro to Swarm » Comprehensive » "The Best Way"*
  • 15. » Starting point » Practical and concrete » Code Samples! » Necessarily limited What This Talk Is:What This Talk Is:
  • 17. » Structure my project? » Minimize divergence between Dev and Prod? » Use environment variables? » Manage sensitive information? » Use a private image registry? » Tag images properly? » Add Lucee extensions? » Configure CI/CD for deployment? » Monitor with FusionReactor? » Handle sessions? » File a tax extension? How Do I...How Do I...
  • 18. It can be doneIt can be done _ಠ_ಠ
  • 19. Begin with the endBegin with the end in mind.in mind. Stephen Covey, The 7 Habits of Highly Effective People, 1989
  • 22. Project StructureProject Structure . ├── .env ├── .gitlab-ci.yml ├── .secrets │   ├── cfml.admin.password.dev │   └── cfml.admin.password.v1 ├── app │   ├── .CFConfig.json │   ├── box.json │   ├── server.json │   └── wwwroot │   └── index.cfm ├── build │   ├── cfml │   │   ├── Dockerfile │   │   └── config │   │   └── extensions │   │   └── extension-loganalyzer-2.3.2.16.lex │   └── deploy-secrets.sh ├── docker-compose.override.yml ├── docker-compose.prod.yml └── docker-compose.yml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ├── .env ├── .secrets │   ├── cfml.admin.password.dev │   └── cfml.admin.password.v1 .1 2 ├── .gitlab-ci.yml3 4 5 6 ├── app7 │   ├── .CFConfig.json8 │   ├── box.json9 │   ├── server.json10 │   └── wwwroot11 │   └── index.cfm12 ├── build13 │   ├── cfml14 │   │   ├── Dockerfile15 │   │   └── config16 │   │   └── extensions17 │   │   └── extension-loganalyzer-2.3.2.16.lex18 │   └── deploy-secrets.sh19 ├── docker-compose.override.yml20 ├── docker-compose.prod.yml21 └── docker-compose.yml22 ├── .gitlab-ci.yml .1 ├── .env2 3 ├── .secrets4 │   ├── cfml.admin.password.dev5 │   └── cfml.admin.password.v16 ├── app7 │   ├── .CFConfig.json8 │   ├── box.json9 │   ├── server.json10 │   └── wwwroot11 │   └── index.cfm12 ├── build13 │   ├── cfml14 │   │   ├── Dockerfile15 │   │   └── config16 │   │   └── extensions17 │   │   └── extension-loganalyzer-2.3.2.16.lex18 │   └── deploy-secrets.sh19 ├── docker-compose.override.yml20 ├── docker-compose.prod.yml21 └── docker-compose.yml22 ├── app │   ├── .CFConfig.json │   ├── box.json │   ├── server.json │   └── wwwroot │   └── index.cfm .1 ├── .env2 ├── .gitlab-ci.yml3 ├── .secrets4 │   ├── cfml.admin.password.dev5 │   └── cfml.admin.password.v16 7 8 9 10 11 12 ├── build13 │   ├── cfml14 │   │   ├── Dockerfile15 │   │   └── config16 │   │   └── extensions17 │   │   └── extension-loganalyzer-2.3.2.16.lex18 │   └── deploy-secrets.sh19 ├── docker-compose.override.yml20 ├── docker-compose.prod.yml21 └── docker-compose.yml22 ├── build │   ├── cfml │   │   ├── Dockerfile │   │   └── config │   │   └── extensions │   │   └── extension-loganalyzer-2.3.2.16.lex │   └── deploy-secrets.sh .1 ├── .env2 ├── .gitlab-ci.yml3 ├── .secrets4 │   ├── cfml.admin.password.dev5 │   └── cfml.admin.password.v16 ├── app7 │   ├── .CFConfig.json8 │   ├── box.json9 │   ├── server.json10 │   └── wwwroot11 │   └── index.cfm12 13 14 15 16 17 18 19 ├── docker-compose.override.yml20 ├── docker-compose.prod.yml21 └── docker-compose.yml22 ├── docker-compose.override.yml ├── docker-compose.prod.yml └── docker-compose.yml .1 ├── .env2 ├── .gitlab-ci.yml3 ├── .secrets4 │   ├── cfml.admin.password.dev5 │   └── cfml.admin.password.v16 ├── app7 │   ├── .CFConfig.json8 │   ├── box.json9 │   ├── server.json10 │   └── wwwroot11 │   └── index.cfm12 ├── build13 │   ├── cfml14 │   │   ├── Dockerfile15 │   │   └── config16 │   │   └── extensions17 │   │   └── extension-loganalyzer-2.3.2.16.lex18 │   └── deploy-secrets.sh19 20 21 22 https://gitlab.com/mjclemente/starter­swarm­cfml
  • 23. Sharing ConfigurationSharing Configuration . ├── docker-compose.override.yml ├── docker-compose.prod.yml └── docker-compose.yml 1 2 3 4 ├── docker-compose.override.yml └── docker-compose.yml .1 2 ├── docker-compose.prod.yml3 4 ├── docker-compose.prod.yml └── docker-compose.yml .1 ├── docker-compose.override.yml2 3 4  Understanding Multiple Compose Files Bret Fisher AMA on docker­compose.override.yml $ docker-compose up Minimize Divergence Between Dev and ProdMinimize Divergence Between Dev and Prod
  • 24. Sharing ConfigurationSharing Configuration $ docker-compose -f docker-compose.yml -f docker-compose.prod.yml up # Works if not dependent on Swarm features 1 2 3 4 5 -f docker-compose.prod.yml $ docker-compose 1 -f docker-compose.yml 2 3 up4 # Works if not dependent on Swarm features5 -f docker-compose.yml $ docker-compose 1 2 -f docker-compose.prod.yml 3 up4 # Works if not dependent on Swarm features5 -f docker-compose.yml -f docker-compose.prod.yml $ docker-compose 1 2 3 up4 # Works if not dependent on Swarm features5 $ docker-compose -f docker-compose.yml -f docker-compose.prod.yml up # Works if not dependent on Swarm features 1 2 3 4 5 docker stack deploy -c docker-compose.yml -c docker-compose.prod.yml test # For Swarm deployments 1 2 3 4 5 -c docker-compose.prod.yml docker stack deploy 1 -c docker-compose.yml 2 3 test4 # For Swarm deployments5 -c docker-compose.yml docker stack deploy 1 2 -c docker-compose.prod.yml 3 test4 # For Swarm deployments5 -c docker-compose.yml -c docker-compose.prod.yml docker stack deploy 1 2 3 test4 # For Swarm deployments5 docker stack deploy -c docker-compose.yml -c docker-compose.prod.yml test # For Swarm deployments 1 2 3 4 5 Minimize Divergence Between Dev and ProdMinimize Divergence Between Dev and Prod
  • 25. version: "3.7" services: cfml: image: "registry.gitlab.com/${CI_PROJE build: context: . dockerfile: ./build/cfml/Dockerfile environment: PORT: 8080 SSL_PORT: 8443 cfconfigfile: .CFConfig.json cfconfig_inspectTemplate: never secrets: - source: cfml.admin.password target: cfml.admin.password ports: - target: 8080 published: 80 - target: 8443 published: 443 networks: internal: driver: overlay secrets: cfml.admin.password: external: true name: cfml.admin.password.v1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 cfconfig_inspectTemplate: never version: "3.7"1 2 services:3 cfml:4 image: "registry.gitlab.com/${CI_PROJE5 build:6 context: .7 dockerfile: ./build/cfml/Dockerfile8 environment:9 PORT: 808010 SSL_PORT: 844311 cfconfigfile: .CFConfig.json12 13 secrets:14 - source: cfml.admin.password15 target: cfml.admin.password16 ports:17 - target: 808018 published: 8019 - target: 844320 published: 44321 22 networks:23 internal:24 driver: overlay25 26 secrets:27 cfml.admin.password:28 external: true29 name: cfml.admin.password.v130 networks: internal: driver: overlay version: "3.7"1 2 services:3 cfml:4 image: "registry.gitlab.com/${CI_PROJE5 build:6 context: .7 dockerfile: ./build/cfml/Dockerfile8 environment:9 PORT: 808010 SSL_PORT: 844311 cfconfigfile: .CFConfig.json12 cfconfig_inspectTemplate: never13 secrets:14 - source: cfml.admin.password15 target: cfml.admin.password16 ports:17 - target: 808018 published: 8019 - target: 844320 published: 44321 22 23 24 25 26 secrets:27 cfml.admin.password:28 external: true29 name: cfml.admin.password.v130 secrets: cfml.admin.password: external: true name: cfml.admin.password.v1 version: "3.7"1 2 services:3 cfml:4 image: "registry.gitlab.com/${CI_PROJE5 build:6 context: .7 dockerfile: ./build/cfml/Dockerfile8 environment:9 PORT: 808010 SSL_PORT: 844311 cfconfigfile: .CFConfig.json12 cfconfig_inspectTemplate: never13 secrets:14 - source: cfml.admin.password15 target: cfml.admin.password16 ports:17 - target: 808018 published: 8019 - target: 844320 published: 44321 22 networks:23 internal:24 driver: overlay25 26 27 28 29 30 version: "3.7" services: cfml: volumes: - ./app:/app environment: cfconfig_inspectTemplate: always ports: - target: 8080 published: 8080 - target: 8443 published: 8443 networks: internal: driver: bridge secrets: cfml.admin.password: external: false file: ./.secrets/cfml.admin.password.dev 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 cfconfig_inspectTemplate: always version: "3.7"1 2 services:3 cfml:4 volumes:5 - ./app:/app6 environment:7 8 ports:9 - target: 808010 published: 808011 - target: 844312 published: 844313 14 networks:15 internal:16 driver: bridge17 18 secrets:19 cfml.admin.password:20 external: false21 file: ./.secrets/cfml.admin.password.dev22 networks: internal: driver: bridge version: "3.7"1 2 services:3 cfml:4 volumes:5 - ./app:/app6 environment:7 cfconfig_inspectTemplate: always8 ports:9 - target: 808010 published: 808011 - target: 844312 published: 844313 14 15 16 17 18 secrets:19 cfml.admin.password:20 external: false21 file: ./.secrets/cfml.admin.password.dev22 secrets: cfml.admin.password: external: false file: ./.secrets/cfml.admin.password.dev version: "3.7"1 2 services:3 cfml:4 volumes:5 - ./app:/app6 environment:7 cfconfig_inspectTemplate: always8 ports:9 - target: 808010 published: 808011 - target: 844312 published: 844313 14 networks:15 internal:16 driver: bridge17 18 19 20 21 22 docker­compose.override.ymldocker­compose.yml
  • 26. the last slidethe last slide was awas a lielie
  • 27. The real worldThe real world doesn't look likedoesn't look like demos.demos. ┻━┻︵(°□°)/ ︵┻━┻
  • 30. Swarm CreationSwarm Creation doctl # Create Docker Droplet doctl compute droplet create test --size 1gb --image docker-18-04 --region nyc1 # List Droplets doctl compute droplet list #Delete a Droplet doctl compute droplet delete 123456 #List SSH Key Ids and Names doctl compute droplet list --format "ID,Name" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 (Official DigitalOcean Command­Line Client)
  • 35. ${Env} in Compose${Env} in Compose image: "registry.gitlab.com/${CI_PROJECT_NAMESPACE}/starter-swarm- cfml/cfml:${BUILD_TAG:-latest}" version: "3.7"1 2 services:3 cfml:4 5 build:6 context: .7 dockerfile: ./build/cfml/Dockerfile8 environment:9 PORT: 808010 SSL_PORT: 844311 cfconfigfile: .CFConfig.json12 cfconfig_inspectTemplate: never13 CF_ADMINPASSWORD: <<SECRET:cfml.admin.password>>14 secrets:15 - source: cfml.admin.password16 target: cfml.admin.password17 environment: PORT: 8080 SSL_PORT: 8443 cfconfigfile: .CFConfig.json cfconfig_inspectTemplate: never CF_ADMINPASSWORD: <<SECRET:cfml.admin.password>> version: "3.7"1 2 services:3 cfml:4 image: "registry.gitlab.com/${CI_PROJECT_NAMESPACE}/starter-swarm- cfml/cfml:${BUILD_TAG:-latest}" 5 build:6 context: .7 dockerfile: ./build/cfml/Dockerfile8 9 10 11 12 13 14 secrets:15 - source: cfml.admin.password16 target: cfml.admin.password17
  • 36. ${Env} in CFConfig.json${Env} in CFConfig.json "adminPassword":"${CF_ADMINPASSWORD}", {1 2 "applicationListener":"modern",3 "applicationMode":"curr2root",4 "applicationTimeout":"1,0,0,0",5 "cacheDefaultFile":"",6 "cacheDefaultFunction":"",7 "cacheDefaultHTTP":"",8 "cacheDefaultInclude":"",9 "cacheDefaultObject":"object",10 "cacheDefaultQuery":"",11 "cacheDefaultResource":"",12 "cacheDefaultTemplate":"",13 "cacheDefaultWebservice":"",14 "caches":{},15 "CGIReadOnly":"true",16 "clientCookies":"true",17 (Same behavior in server.json)
  • 37. Env variables prone to leakEnv variables prone to leak
  • 38. Docker Swarm SecretsDocker Swarm Secrets » Immutable by design » Account for rotation » Account for Dev and Production » Team conventions are essential https://docs.docker.com/engine/swarm/secrets/ https://docs.docker.com/compose/compose­file/#secrets
  • 39. secrets: cfml.admin.password: external: true name: cfml.admin.password.v1 secrets: cfml.admin.password: external: false file: ./.secrets/cfml.admin.password.dev docker­compose.override.ymldocker­compose.yml version: "3.7" services: cfml: ... environment: PORT: 8080 SSL_PORT: 8443 cfconfigfile: .CFConfig.json cfconfig_inspectTemplate: never CF_ADMINPASSWORD: <<SECRET:cfml.admin.password>> secrets: - source: cfml.admin.password target: cfml.admin.password
  • 40. ( ••)( ••) ( ••)>⌐■-■( ••)>⌐■-■ (⌐■_■) #Secrets!(⌐■_■) #Secrets! https://gitlab.com/mjclemente/starter­swarm­cfml/blob/master/build/deploy­secrets.sh
  • 41. CI/CD with Gitlab RunnersCI/CD with Gitlab Runners » Configured via .gitlab-ci.yml » Run automagically » Multiple types of runners » Use a dedicated SSH Key https://docs.gitlab.com/ee/ci/quick_start/
  • 43. .gitlab­ci.yml » File containing all definitions of how your project should be built https://docs.gitlab.com/ee/ci/yaml/
  • 44. before_script: before_script: ## We're gonna log into the gitlab registry, as that's where these images are stored - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com ## Git needed to get the date from the commit sha - apk add git ## So we can see what's going on in the logs - docker info ## setup environment variables - [configuration continues] 1 2 3 4 5 6 7 8 9 - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com before_script:1 ## We're gonna log into the gitlab registry, as that's where these images are stored 2 3 ## Git needed to get the date from the commit sha4 - apk add git5 ## So we can see what's going on in the logs6 - docker info7 ## setup environment variables8 - [configuration continues]9 - apk add git before_script:1 ## We're gonna log into the gitlab registry, as that's where these images are stored 2 - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com 3 ## Git needed to get the date from the commit sha4 5 ## So we can see what's going on in the logs6 - docker info7 ## setup environment variables8 - [configuration continues]9 before_script: ## We're gonna log into the gitlab registry, as that's where these images are stored - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com ## Git needed to get the date from the commit sha - apk add git ## So we can see what's going on in the logs - docker info ## setup environment variables - [configuration continues] 1 2 3 4 5 6 7 8 9 Getting everything set up .gitlab­ci.yml https://docs.gitlab.com/ee/ci/yaml/#before_script­and­after_script
  • 45. Tagging Custom ImagesTagging Custom Images » Don't just use "latest" » Combination of date and commit before_script: - export COMMIT_TIME=$(git show -s --format=%ci $CI_COMMIT_SHA) - export COMMIT_TIME_SHORT=$(echo $COMMIT_TIME | head -c10) - export BUILD_TAG="${COMMIT_TIME_SHORT}_$CI_COMMIT_SHORT_SHA" 1 - [earlier configuration]2 ## Use git `show` with --format=%ci to get ISO 8601 date3 4 ## Use first 10 characters of the datetime (ie: 2019-03-19)5 6 7 - export COMMIT_TIME=$(git show -s --format=%ci $CI_COMMIT_SHA) before_script:1 - [earlier configuration]2 ## Use git `show` with --format=%ci to get ISO 8601 date3 4 ## Use first 10 characters of the datetime (ie: 2019-03-19)5 - export COMMIT_TIME_SHORT=$(echo $COMMIT_TIME | head -c10)6 - export BUILD_TAG="${COMMIT_TIME_SHORT}_$CI_COMMIT_SHORT_SHA"7 - export COMMIT_TIME_SHORT=$(echo $COMMIT_TIME | head -c10) before_script:1 - [earlier configuration]2 ## Use git `show` with --format=%ci to get ISO 8601 date3 - export COMMIT_TIME=$(git show -s --format=%ci $CI_COMMIT_SHA)4 ## Use first 10 characters of the datetime (ie: 2019-03-19)5 6 - export BUILD_TAG="${COMMIT_TIME_SHORT}_$CI_COMMIT_SHORT_SHA"7 - export BUILD_TAG="${COMMIT_TIME_SHORT}_$CI_COMMIT_SHORT_SHA" before_script:1 - [earlier configuration]2 ## Use git `show` with --format=%ci to get ISO 8601 date3 - export COMMIT_TIME=$(git show -s --format=%ci $CI_COMMIT_SHA)4 ## Use first 10 characters of the datetime (ie: 2019-03-19)5 - export COMMIT_TIME_SHORT=$(echo $COMMIT_TIME | head -c10)6 7 .gitlab­ci.yml
  • 46. Control Pipeline StagesControl Pipeline Stages deploy: stage: deploy only: - deploy except: variables: - $CI_COMMIT_MESSAGE =~ /Initial commit/i - $CI_COMMIT_MESSAGE =~ /skip deploy/i - $CI_COMMIT_MESSAGE =~ /don't deploy/i https://docs.gitlab.com/ee/ci/yaml/#onlyexcept­basic .gitlab­ci.yml
  • 47. Building Custom ImagesBuilding Custom Images build: stage: build only: - deploy script: ## Build the image, with the build tag and the latest tag - docker build --tag $CONTAINER_IMAGE:$BUILD_TAG --tag $CONTAINER_IMAGE:latest -f ./build/cfml/Dockerfile . ## List images, so we can confirm success - docker image ls ## Push with the build tag - docker push $CONTAINER_IMAGE:$BUILD_TAG ## Push with latest - docker push $CONTAINER_IMAGE:latest .gitlab­ci.yml
  • 49. Stack DeploymentStack Deployment deploy: stage: deploy script: - [a lot of SSH related config] ## Enable SSH functionality made possible in 18.0.9 to switch our context to the remote server - export DOCKER_HOST=ssh://root@${HOST_IP} ## Deploy the stack - registry auth is for gitlab - docker stack deploy -c docker-compose.yml -c docker- compose.prod.yml basetest --with-registry-auth .gitlab­ci.yml
  • 50. » Swarm's missing UI » Configuration and management » Separate from application stack PortainerPortainer
  • 51. » » » Hybrid license Easy installation (ForgeBox) Some manual configuration FusionReactor (Cloud)FusionReactor (Cloud)
  • 52. » Required in multi-node Swarms » Free options » Provided via (beta) Lucee Extensions » Paid options are superior Sessions and CachingSessions and Caching https://blog.mattclemente.com/2018/08/17/install­lucee­extensions­on­commandbox­docker­containers.html
  • 54.
  • 55. All things areAll things are difficult before theydifficult before they are easy.are easy. Dr. Thomas Fuller, Gnomologia, 1732
  • 56. Try This At HomeTry This At Home Building a Personal Docker SwarmBuilding a Personal Docker Swarm Matthew Clemente @mjclemente @mjclemente84 blog.mattclemente.com @mjclemente