Try This At Home
Building Your Own ColdFusion Swarm
Matthew Clemente
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/4559731/GitHub-Mark-Light-120px-plus.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/4561715/Twitter_Social_Icon_Circle_Color.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6037393/Slack-Mark-Monochrome-White.png)
A Familiar Story
- Adobe ColdFusion 10 /11
- Windows Server 2008
- Microsoft IIS
- Rackspace
- FTP Deployments
- Dev Server (in basement)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6033254/nyan-whale-docker.gif)
Every Conference
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6033278/route-reversed.png)
Looking for Direction
Legacy Infrastructure
Scriptable
Scalable
Containerized
12-Factor App
CI/CD
Microservices
Bret Fisher Resources
![Bret Fisher](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6032815/bret-fisher.jpeg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6032978/DCEU17_logo_simple-white-v2.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6032982/dockercon-us-2018.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6033185/udemy-2-logo-png-transparent-white.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6033185/udemy-2-logo-png-transparent-white.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6033185/udemy-2-logo-png-transparent-white.png)
Learned a Lot
Still don't know how to do this.
¯\_(ツ)_/¯
You'll learn more on the first day of production than the previous two months.
Bret Fisher, Taking Docker to Production, DockerCon Europe 2017
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6025665/paraphrased-white.png)
Doing
is
Learning
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6037576/loop-arrows-2-half.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6037579/loop-arrows-2-half-2.png)
All genuine learning comes through experience.
John Dewey, Experience & Education, 1938
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6025665/paraphrased-white.png)
How do I actually do this?
Don't tell me that it's possible without showing me how!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6035487/say-cattle-one-more-time.jpg)
![](https://media2.giphy.com/media/5wWf7H89PisM6An8UAU/giphy.gif)
Goal
Learning By Doing
Concrete Examples
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/5241096/up-arrow-3-white.png)
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:
Tooling and Services
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6028225/DO_Logo_Vertical_Blue.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6028230/logo-portainer_alt.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6028238/gitlab-logo-white-stacked-rgb.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6028240/swarm-logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6028267/commandbox-logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6028274/fusionreactor-logo-white.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6028346/cf-logo-v-rgb-rev.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6083142/Consul_PrimaryLogo_FullColor.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6083147/traefik.logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6083288/NGINX-logo-rgb-large.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6083197/lets-encrypt-logo-standard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6412723/adobe-coldfusion-2018.png)
How Do I...
- 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?
It can be done
ಠಿ_ಠ
Begin with the end in mind.
Stephen Covey, The 7 Habits of Highly Effective People, 1989
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/5312183/giphy-white.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/5310748/Full-transparent-background-1000.png)
Project 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
│ └── deploy-secrets.sh
├── docker-compose.override.yml
├── docker-compose.debug.yml
└── docker-compose.yml
Sharing Configuration
.
├── docker-compose.override.yml
├── docker-compose.debug.yml
└── docker-compose.yml
$ docker-compose up
Minimize Divergence Between Dev and Prod
version: "3.7"
services:
cfml:
image: "registry.gitlab.com/${CI_PROJECT_NAMESPACE}/starter-swarm-coldfusion/cfml:${BUILD_TAG:-latest}"
build:
context: .
dockerfile: ./build/cfml/Dockerfile
environment:
PORT: 8080
SSL_PORT: 8443
cfconfigfile: .CFConfig.json
cfconfig_inspectTemplate: never
secrets:
- 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
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
docker-compose.override.yml
docker-compose.yml
the last slide was a lie 🤥
The real world doesn't look like demos.
┻━┻︵ \(°□°)/ ︵ ┻━┻
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6028225/DO_Logo_Vertical_Blue.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6041262/digitalocean-swarm-creation-gui.png)
Swarm Creation
Swarm Creation
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6028218/DO_Logo_Vertical_White.png)
# 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"
(Official DigitalOcean Command-Line Client)
Swarm Creation
![DigitalOcean Swarm Creation](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6034723/do-swarm-create-prompt.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6028218/DO_Logo_Vertical_White.png)
![](https://media0.giphy.com/media/9tTEqj99CSMsE/giphy.gif)
Swarm Initialized
{CONFIG}
CODE
A litmus test is whether the codebase could be made open source without compromising any credentials.
Adam Wiggins, The Twelve-Factor App, 2017
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6025665/paraphrased-white.png)
Environment Variables
- Environment for configuration
- Modular and easy to change
- Managed in .env file
.env
CI_PROJECT_NAMESPACE=mjclemente
OTHER_SETTING=
FOO=bar
${Env} in Compose
services:
cfml:
image: "registry.gitlab.com/${CI_PROJECT_NAMESPACE}/starter-swarm-coldfusion/cfml:${BUILD_TAG:-latest}"
build:
context: .
dockerfile: ./build/cfml/Dockerfile
environment:
PORT: 8080
SSL_PORT: 8443
cfconfigfile: .CFConfig.json
cfconfig_inspectTemplate: never
CF_ADMINPASSWORD: <<SECRET:cfml.admin.password>>
secrets:
- cfml.admin.password
${Env} in CFConfig.json
{
"adminPassword": "${CF_ADMINPASSWORD}",
"adminAllowConcurrentLogin": true,
"adminAllowedIPList": "",
"adminLoginRequired": true,
"adminRDSEnabled": "false",
"adminRDSLoginRequired": "false",
"adminRDSUserIDRequired": true,
"adminRootUserID": "admin",
"adminUserIDRequired": false,
"ajaxDebugWindowEnabled": false,
"allowApplicationVarsInServletContext": false,
"allowExtraAttributesInAttrColl": true,
"applicationMangement": true,
"applicationMaximumTimeout": "2,0,0,0",
"applicationMode": "curr2driveroot",
"applicationTimeout": "2,0,0,0",
(Same behavior in server.json)
Env variables prone to leak
![](https://media3.giphy.com/media/lVBtp4SRW6rvDHf1b6/giphy.gif)
Docker Swarm Secrets
- Immutable by design
- Account for rotation
- Account for Dev and Production
- Team conventions are essential
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.yml
docker-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:
- cfml.admin.password
( ••)
( ••)>⌐■-■
(⌐■_■) #Secrets!
CI/CD with Gitlab Runners
- Configured via .gitlab-ci.yml
- Run automagically
- Multiple types of runners
- Use a dedicated SSH Key
₍₍ ᕕ( ಠ‿ಠ)ᕗ
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/4851714/gitlab-logo-square.png)
.gitlab-ci.yml
- File containing all definitions of how your project should be built
before_script:
before_script:
## We're gonna log into the gitlab registry, as that's where these images are stored
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
## 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]
Getting everything set up
.gitlab-ci.yml
Tagging Custom Images
- Don't just use "latest"
- Combination of date and commit
before_script:
- [earlier configuration]
## Use git `show` with --format=%ci to get ISO 8601 date
- export COMMIT_TIME=$(git show -s --format=%ci $CI_COMMIT_SHA)
## Use first 10 characters of the datetime (ie: 2019-03-19)
- export COMMIT_TIME_SHORT=$(echo $COMMIT_TIME | head -c10)
- export BUILD_TAG="${COMMIT_TIME_SHORT}_$CI_COMMIT_SHORT_SHA"
.gitlab-ci.yml
Control 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
.gitlab-ci.yml
Building Custom Images
build:
stage: build
only:
- deploy
script:
## Build the image, with BUILD_TAG and latest tags
- 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
![](https://media3.giphy.com/media/CDZwopbecAbIc/giphy.gif)
Stack Deployment
Stack 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 basetest --with-registry-auth
.gitlab-ci.yml
- Swarm's missing UI
- Configuration and management
- Separate from application stack
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6083079/portainer-official-screenshot-short.png)
Portainer
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6083128/fusionreactor-official-cloud-metrics-screenshot-short.png)
FusionReactor (Cloud)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6028274/fusionreactor-logo-white.png)
- External Storage
- Required in multi-node Swarms
- Built-in support in ColdFusion 2018
Sessions and Caching
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6084963/memcached.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6085017/redis-logo.png)
SSL
(Zero-config tool to make locally trusted development certificates)
+
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6083251/production-stamp-white.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6083252/development-stamp-white.png)
![](https://media0.giphy.com/media/C4wDXSJjt0ZKU/giphy.gif)
All things are difficult before they are easy.
Dr. Thomas Fuller, Gnomologia, 1732
Try This At Home
Building Your Own ColdFusion Swarm
Matthew Clemente
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/4559731/GitHub-Mark-Light-120px-plus.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/4561715/Twitter_Social_Icon_Circle_Color.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/755503/images/6037393/Slack-Mark-Monochrome-White.png)
Try This At Home: Building Your Own ColdFusion Swarm
By mjclemente
Try This At Home: Building Your Own ColdFusion Swarm
Presentation for Adobe ColdFusion Summit 2019
- 3,913