Skip to main content

I have a Docker Compose setup

Follow this guide to package your application as a Helm chart using the docker-compose.yaml file that you already have. We will use a simple example containing an application connected to a PostgreSQL database.

compose.yml
volumes:
pg_app_data:

services:
example-app:
image: public.aws.ecr/<repository_id>/example-app:1.0.0
environment:
DB_HOST: database
DB_NAME: app_db
DB_USER: postrgres
DB_PASS: postrgres
DB_PORT: 5432
APP_PORT: 8000
ports:
- '8000:8000'
depends_on:
- database

database:
image: postgres:14.8-alpine3.18
environment:
POSTGRES_DB: app_db
POSTGRES_USER: postrgres
POSTGRES_PASSWORD: postgres
volumes:
- pg_app_data:/var/lib/postgresql/data
ports:
- '5432:5432'

Create a helm chart from your Docker Compose​

  1. Create a directory and set up the Helm Chart Directory Structure in it using helm create example-app-chart command.
  2. Write a deployment object (kubernetes manifest) for each of the services from docker-compose.yaml file, in the templates directory.They define the desired state for application pods, ensuring that the specified number of replicas of the application is running at any given time.
templates/deployments.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres-statefulset
spec:
serviceName: '{{ .Values.db.host }}'
replicas: 1
selector:
matchLabels:
app: postgres-db
template:
metadata:
labels:
app: postgres-db
spec:
containers:
- name: postgres-container
image: postgres:14.8-alpine3.18
env:
- name: POSTGRES_DB
value: '{{ .Values.db.name }}'
- name: POSTGRES_USER
value: '{{ .Values.db.user }}'
- name: POSTGRES_PASSWORD
value: '{{ .Values.db.pass }}'
- name: PGDATA
value: /var/lib/postgresql/data/todo/
ports:
- containerPort: { { .Values.db.port } }
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data

---
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-app-deployment
spec:
replicas: { { .Values.replicaCount } }
selector:
matchLabels:
app: example-app
template:
metadata:
labels:
app: example-app
spec:
containers:
- name: example-app-container
image: '{{ .Values.example-app.image }}:{{ .Values.example-app.imageVersion }}'
env:
- name: DB_HOST
value: '{{ .Values.db.host }}'
- name: DB_PORT
value: '{{ .Values.db.port }}'
- name: DB_NAME
value: '{{ .Values.db.name }}'
- name: DB_USER
value: '{{ .Values.db.user }}'
- name: DB_PASS
value: '{{ .Values.db.pass }}'
- name: HELM_VERSION
value: '{{ .Chart.Version }}'
- name: APP_PORT
value: '{{ .Values.example-app.service.port }}'

ports:
containerPort: { { .Values.example-app.service.port } }
initContainers:
- name: check-db-ready
image: postgres:14.8-alpine3.18
env:
- name: POSTGRES_HOST
value: '{{ .Values.db.host }}'
- name: POSTGRES_PORT
value: '{{ .Values.db.port }}'
command: [
'sh',
'-c',
'echo Checking if postgres is up; until pg_isready -h $POSTGRES_HOST -p $POSTGRES_PORT;
do echo Waiting for postgres database to be up...; sleep 2; done; echo Postgres is up!',
]
note

We can see that example-app service depends on the database service in the docker-compose file. The depends_on field from Docker Compose, which defines dependencies between services, can be mimicked using initContainers in a Deployment object. initContainers run to completion before the main application containers start. They can be used to ensure that a dependent service is ready before starting the main application.

  1. Write a service object (kubernetes manifest) for each of the services from docker-compose.yaml file, in the templates directory, to expose the ports your services run on accordingly.
templates/services.yaml
apiVersion: v1
kind: Service
metadata:
name: example-app-service
spec:
type: { { .Values.example-app.service.type } }
selector:
app: example-app
ports:
- protocol: TCP
port: { { .Values.example-app.service.port } }
targetPort: { { .Values.example-app.service.targetPort } }

---
apiVersion: v1
kind: Service
metadata:
name: postgres-service
spec:
selector:
app: postgres-db
ports:
- protocol: TCP
port: 5432
note

The service.type field specifies how a service is exposed. Learn more about service types and their values

  1. Create values.yaml file with appropriate values required by your helm chart
values.yaml
replicaCount: 1

example-app:
service:
type: NodePort
port: 8000
targetPort: 8000
image: public.ecr.aws/<repository_id>/example-app
imageVersion: 1.0.0

db:
host: postgres-service
port: 5432
name: app_db
user: postgres
pass: postgres
  1. Now that you've created a helm chart using your Docker Compose follow this guide to publish your helm chart and get it deployed in a Localops application environment.

Next Steps​