-
Notifications
You must be signed in to change notification settings - Fork 626
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.ymltodocker-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