-
Notifications
You must be signed in to change notification settings - Fork 635
Best practices
Some packages aren't build in the most efficient way to take profit of all rancher catalog features.
This document is intended to be a guide to build a community catalog following best practices. It start showing a basic initial package and will guide on how to improve it adding recommended practices.
Lets start with a simple example of a web service with a db for persistence.
- docker-compose.yml
version: '2'
services:
web:
image: <web_image>:latest
ports:
- ${web_port}:80
environment:
DB_HOST: db
DB_PORT: ${db_port}
DB_NAME: demo
DB_USER: user
DB_PASS: pass
links:
- db:db
db:
image: <db_image>
ports:
- ${db_port}:${db_port}
environment:
DB_PORT: ${db_port}
DB_NAME: demo
DB_USER: user
DB_PASS: pass
Note: DB_HOST could be static value. db link is the variable part.
- rancher-compose.yml
version: '2'
catalog:
name: <name>
version: <version>
description: <description>
uuid: <uuid>
questions:
- variable: web_port
description: "public port to access the web"
label: "Web Port"
required: true
default: "80"
type: "int"
- variable: db_port
description: "public port to access the db"
label: "Db Port"
required: true
default: "3306"
type: "int"
services:
web:
scale: 1
retain_ip: true
db:
scale: 1
retain_ip: true
Lets see package improvements points and recommended practices.
Packages has to be easy reproducible and latest isn't. Use a concrete version for every single service. Control package version with package version.
-
Set web image
image: <web_image>:<web_version>
-
Set db image
image: <db_image>:<db_version>
Tcp and http healtchecks are available.
When you start a service with healthcheck, service has an additional state that is Initializing
, that is the time between you start the container until service is started. Once healthcheck return ok, service state transition from Initializing
to Started
.
- http health check for web service. Needs 2XX or 3XX response code.
health_check:
port: 80
interval: 5000
unhealthy_threshold: 3
initializing_timeout: 60000
request_line: 'GET / HTTP/1.0'
healthy_threshold: 2
response_timeout: 5000
reinitializing_timeout: 60000
- tcp health check, for db service
health_check:
healthy_threshold: 2
response_timeout: 2000
port: ${db_port}
unhealthy_threshold: 3
initializing_timeout: 60000
interval: 2000
strategy: recreate
reinitializing_timeout: 60000
Note: If your service take mora than 60 seconds to start, adjust accordingly initializing_timeout (ms)
and reinitializing_timeout (ms)
in healtcheck parameters.
To provide versatility, don't hardcode variables value. Use catalog questions with default values instead.
- Map catalog question values to web service
environment:
DB_HOST: db
DB_PORT: ${db_port}
DB_NAME: ${db_name}
DB_USER: ${db_user}
DB_PASS: ${db_pass}
- Map catalog question values to db service
environment:
DB_PORT: ${db_port}
DB_NAME: ${db_name}
DB_USER: ${db_user}
DB_PASS: ${db_pass}
- Add questions to rancher-compose
- variable: db_name
description: "db name to connect"
label: "Db Name"
required: true
default: "demo"
type: "string"
- variable: db_user
description: "db user to auth"
label: "Db User"
required: true
default: "user"
type: "string"
- variable: db_pass
description: "db pass to auth"
label: "Db Password"
required: true
default: "pass"
type: "password"
Instead of exposing port directly from the service docker, use lb.
- Add lb service
lb:
image: rancher/lb-service-haproxy:v0.6.4
ports:
- ${web_port}:${web_port}/tcp
- ${db_port}:${db_port}/tcp
- Configure lb service
lb:
scale: 1
start_on_create: true
lb_config:
certs: []
port_rules:
- priority: 1
protocol: http
service: web
source_port: ${web_port}
target_port: 80
- priority: 2
protocol: tcp
service: db
source_port: ${db_port}
target_port: ${db_port}
health_check:
healthy_threshold: 2
response_timeout: 2000
port: 42
unhealthy_threshold: 3
initializing_timeout: 60000
interval: 2000
reinitializing_timeout: 60000
Do you really need to expose db port?? Probably not....
- Redefine lb service
lb:
image: rancher/lb-service-haproxy:v0.6.4
ports:
- ${web_port}:${web_port}/tcp
- Reconfigure lb service
lb:
scale: 1
start_on_create: true
lb_config:
certs: []
port_rules:
- priority: 1
protocol: http
service: web
source_port: ${web_port}
target_port: 80
health_check:
healthy_threshold: 2
response_timeout: 2000
port: 42
unhealthy_threshold: 3
initializing_timeout: 60000
interval: 2000
reinitializing_timeout: 60000
Depending of the service, may need volumes to manage persistence properly. Package would be more versatile if you could choose different drivers for service volumes.
- Add volume for web data
volumes:
- web_data:<PATH>
- Add volume for db data
volumes:
- db_data:<PATH>
- Add volumes definition with selectable driver
volumes:
web_data:
driver: ${volume_driver}
db_data:
driver: ${volume_driver}
per_container: true
Note: By default, a volume will be shared between all service instances that use it. All hosts needs access.
If every service instance needs its own volume, use volume param per_container: true
.
- Add volume driver question.
- variable: volume_driver
description: "Volume driver to use with this service"
label: "Volume driver"
required: true
default: "local"
type: enum
options:
- local
- rancher-nfs
- rancher-efs
- rancher-ebs
Note: Recommended enum type to avoid typo.
Latests catalog version permits to use go templating in docker-compose.yml to allow dynamism in catalog packages.
Example feature: Reuse already created db packages and link service, instead of deploying db service.
Logic: if we set db_link variable, we configure our service to connect with an external db. If not, we deploy an internal database service and its volume.
-
Rename
docker-compose.yml
todocker-compose.yml.tpl
-
Add go templating logic for services
{{- if ne .Values.db_link ""}}
external_links:
- ${db_link}:db
{{- else}}
links:
- db:db
db:
image: <db_image>:<db_version>
volumes:
- db_data:<PATH>
environment:
DB_PORT: ${db_port}
DB_NAME: ${db_name}
DB_USER: ${db_user}
DB_PASS: ${db_pass}
{{- end}}
- Add go templating logic for db volume
{{- if eq .Values.db_link ""}}
db_data:
driver: ${volume_driver}
per_container: true
{{- end}}
- Add db link question
- variable: "db_link"
description: |
External db link
label: "External db"
default: ""
required: false
type: "service"
This is the final package definition with all improvements applied.
- docker-compose.yml.tpl
version: '2'
services:
web:
image: <web_image>:<web_version>
volumes:
- web_data:<PATH>
environment:
DB_HOST: db
DB_PORT: ${db_port}
DB_NAME: ${db_name}
DB_USER: ${db_user}
DB_PASS: ${db_pass}
{{- if ne .Values.db_link ""}}
external_links:
- ${db_link}:db
{{- else}}
links:
- db:db
db:
image: <db_image>:<db_version>
volumes:
- db_data:<PATH>
environment:
DB_PORT: ${db_port}
DB_NAME: ${db_name}
DB_USER: ${db_user}
DB_PASS: ${db_pass}
{{- end}}
lb:
image: rancher/lb-service-haproxy:v0.6.4
ports:
- ${web_port}:${web_port}/tcp
volumes:
web_data:
driver: ${volume_driver}
{{- if eq .Values.db_link ""}}
db_data:
driver: ${volume_driver}
per_container: true
{{- end}}
- rancher-compose.yml
version: '2'
catalog:
name: <name>
version: <version>
description: <description>
uuid: <uuid>
questions:
- variable: web_port
description: "public port to access the web"
label: "Web Port"
required: true
default: "80"
type: "int"
- variable: db_port
description: "public port to access the db"
label: "Db Port"
required: true
default: "3306"
type: "int"
- variable: db_name
description: "db name to connect"
label: "Db Name"
required: true
default: "demo"
type: "string"
- variable: db_user
description: "db user to auth"
label: "Db User"
required: true
default: "user"
type: "string"
- variable: db_pass
description: "db pass to auth"
label: "Db Password"
required: true
default: "pass"
type: "password"
- variable: volume_driver
description: "Volume driver to use with this service"
label: "Volume driver"
required: true
default: "local"
type: enum
options:
- local
- rancher-nfs
- rancher-efs
- rancher-ebs
- variable: "db_link"
description: |
External db link
label: "External db"
default: ""
required: false
type: "service"
services:
web:
scale: 1
retain_ip: true
health_check:
port: 80
interval: 5000
unhealthy_threshold: 3
initializing_timeout: 60000
request_line: 'GET / HTTP/1.0'
healthy_threshold: 2
response_timeout: 5000
reinitializing_timeout: 60000
db:
scale: 1
retain_ip: true
health_check:
healthy_threshold: 2
response_timeout: 2000
port: ${db_port}
unhealthy_threshold: 3
initializing_timeout: 60000
interval: 2000
strategy: recreate
reinitializing_timeout: 60000
lb:
scale: 1
start_on_create: true
lb_config:
certs: []
port_rules:
- priority: 1
protocol: http
service: web
source_port: ${web_port}
target_port: 80
health_check:
healthy_threshold: 2
response_timeout: 2000
port: 42
unhealthy_threshold: 3
initializing_timeout: 60000
interval: 2000
reinitializing_timeout: 60000