---
layout: default
permalink: /user-guide/
title: User Guide
redirect_from:
  - /docs/user-guide.md/
  - /docs/user-guide/
---

# User Guide

## Table of contents

* [Kompose conversion example](#kompose-conversion-example)
* [CLI Modifications](#cli-modifications)
* [Labels](#labels)
* [Restart Policy](#restart-policy)
* [Building and Pushing Images](#building-and-pushing-images)

## Kompose Conversion Example

Kompose has support for two providers: OpenShift and Kubernetes.
You can choose a targeted provider using global option `--provider`. If no provider is specified, Kubernetes is set by default.

### Kubernetes

```sh
$ kompose --file compose.yaml convert
```

You can also provide multiple compose files at the same time:

```sh
$ kompose -f compose.yaml -f compose.yaml convert
```

When multiple compose files are provided the configuration is merged. Any configuration that is common will be over ridden by subsequent file.

You can provide your compose files via environment variables as following:
```sh
$ COMPOSE_FILE="compose.yaml alternative-compose.yaml" kompose convert
```

### OpenShift

```sh
$ kompose --provider openshift --file compose.yaml convert
```

## CLI Modifications

On the command line, you can modify the output of the generated YAML. For example, using alternative controllers such as [Replication Controllers](http://kubernetes.io/docs/user-guide/replication-controller/) objects, [Daemon Sets](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/), or [Statefulset](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/).


Daemon Set example:

```sh
$ kompose convert --controller daemonSet
```

A full list of these options can be found on `kompose convert --help`.

## Labels

`kompose` supports Kompose-specific labels within the `compose.yaml` file to get you the rest of the way there.

Labels are an important kompose concept as they allow you to add Kubernetes modifications without having to edit the YAML afterwards. For example, adding an init container, or a custom readiness check.

| Key / Value | Description / Example |
|-----|-------------|
| [`kompose.controller.port.expose`](#komposecontrollerportexpose) | Expose as hostPort on the controller (not recommended) |
| `Boolean` | `false` |
| [`kompose.controller.type`](#komposecontrollertype) | Type of the controller |
| `String` | `deployment`, `daemonset`, `replicationcontroller`, `statefulset` |
| [`kompose.cronjob.backoff_limit`](#komposecronjobbackoff_limit) | Number of retries before marked as failed |
| `Integer` | `6` |
| [`kompose.cronjob.concurrency_policy`](#komposecronjobconcurrency_policy) | Handling of concurrent jobs |
| `String` | `Forbid`, `Allow`, `Never` |
| [`kompose.cronjob.schedule`](#komposecronjobschedule) | Schedule |
| `String` | `1 * * * *` |
| [`kompose.hpa.cpu`](#komposehpacpu) | CPU utilization percentage that triggers autoscaling |
| `Percentage` | `50%` |
| [`kompose.hpa.memory`](#komposehpamemory) | Memory utilization threshold that triggers autoscaling |
| `String` | `200Mi` |
| [`kompose.hpa.replicas.max`](#komposehpareplicasmax) | Max pod replicas for Horizontal Pod Autoscaler |
| `Integer` | `10` |
| [`kompose.hpa.replicas.min`](#komposehpareplicasmin) | Min pod replicas for Horizontal Pod Autoscaler |
| `Integer` | `2` |
| [`kompose.image-pull-policy`](#komposeimage-pull-policy) | Policy for pulling images |
| `String` | `Always`, `IfNotPresent`, `Never` |
| [`kompose.image-pull-secret`](#komposeimage-pull-secret) | Secret to be used for pulling images from a private registry |
| `String` | `myregistrykey` |
| [`kompose.init.containers.command`](#komposeinitcontainerscommand) | Command to be executed |
| `Array` | `["printenv"]` |
| [`kompose.init.containers.image`](#komposeinitcontainersimage) | Image to be used |
| `String` | `busybox` |
| [`kompose.init.containers.name`](#komposeinitcontainersname) | Name assigned |
| `String` | `init-mydb` |
| [`kompose.security-context.fsgroup`](#komposesecurity-contextfsgroup) | Filesystem group ID for the pods' volumes |
| `Integer` | `1001` |
| [`kompose.service.external-traffic-policy`](#komposeserviceexternal-traffic-policy) | Policy to route external traffic |
| `String` | `cluster`, `local` |
| [`kompose.service.expose`](#komposeserviceexpose) | Creates a Ingress or Route. Accepts domain or 'true' for auto-generating a domain. |
| `String` | `true,domain1.com,domain2.com` |
| [`kompose.service.expose.ingress-class-name`](#komposeserviceexposeingress-class-name) | Ingress class to be used for exposing services |
| `String` | `nginx` |
| [`kompose.service.expose.tls-secret`](#komposeserviceexposetls-secret) | TLS secret for securing ingress |
| `String` | `my-tls-secret` |
| [`kompose.service.group`](#komposeservicegroup) | Label to group multiple containers in a single pod |
| `String` | `mygroup` |
| [`kompose.service.healthcheck.liveness.http_get_path`](#komposeservicehealthchecklivenesshttp_get_path) | HTTP GET path for liveness probe |
| `String` | `/health` |
| [`kompose.service.healthcheck.liveness.http_get_port`](#komposeservicehealthchecklivenesshttp_get_port) | HTTP GET port for liveness probe |
| `Integer` | `8080` |
| [`kompose.service.healthcheck.liveness.tcp_port`](#komposeservicehealthchecklivenesstcp_port) | TCP socket port for liveness probe |
| `Integer` | `3306` |
| [`kompose.service.healthcheck.readiness.disable`](#komposeservicehealthcheckreadinessdisable) | Whether to disable the readiness probe |
| `Boolean` | `true` |
| [`kompose.service.healthcheck.readiness.http_get_path`](#komposeservicehealthcheckreadinesshttp_get_path) | HTTP GET path for readiness probe |
| `String` | `/ready` |
| [`kompose.service.healthcheck.readiness.http_get_port`](#komposeservicehealthcheckreadinesshttp_get_port) | HTTP GET port for readiness probe |
| `Integer` | `8081` |
| [`kompose.service.healthcheck.readiness.interval`](#komposeservicehealthcheckreadinessinterval) | Interval between readiness checks |
| `Duration` | `10s` |
| [`kompose.service.healthcheck.readiness.retries`](#komposeservicehealthcheckreadinessretries) | Number of times readiness probe should retry before failing |
| `Integer` | `3` |
| [`kompose.service.healthcheck.readiness.start_period`](#komposeservicehealthcheckreadinessstart_period) | Initial delay before starting the readiness probe |
| `Duration` | `30s` |
| [`kompose.service.healthcheck.readiness.tcp_port`](#komposeservicehealthcheckreadinesstcp_port) | TCP socket port for readiness probe |
| `Integer` | `3307` |
| [`kompose.service.healthcheck.readiness.test`](#komposeservicehealthcheckreadinesstest) | Command or script run by the readiness probe |
| `Array` | `["CMD", "echo", "OK"]` |
| [`kompose.service.healthcheck.readiness.timeout`](#komposeservicehealthcheckreadinesstimeout) | Timeout for a single readiness probe |
| `Duration` | `5s` |
| [`kompose.service.nodeport.port`](#komposeservicenodeportport) | Specific port number to be used as NodePort |
| `Integer` | `30000` |
| [`kompose.service.type`](#komposeservicetype) | Type of service |
| `String` | `nodeport`, `clusterip`, `loadbalancer`, `headless` |
| [`kompose.volume.size`](#komposevolumesize) | Size of the volume |
| `String` | `1Gi` |
| [`kompose.volume.storage-class-name`](#komposevolumestorage-class-name) | StorageClassName for provisioning volumes |
| `String` | `standard` |
| [`kompose.volume.subpath`](#komposevolumesubpath) | Subpath inside the mounted volume |
| `String` | `/data` |
| [`kompose.volume.type`](#komposevolumetype) | Type of Kubernetes volume |
| `String` | `configMap`, `persistentVolumeClaim`, `emptyDir`, `hostPath` |

### kompose.controller.port.expose

```yaml
services:
  web:
    image: wordpress:latest
    ports:
      - '80:80'
    labels:
      kompose.controller.expose.port: true
```

### kompose.controller.type

```yaml
services:
  web:
    image: wordpress:latest
    ports:
      - '80:80'
    labels:
      kompose.controller.type: deployment
```

### kompose.cronjob.backoff_limit

```yaml
services:
  cron-job:
    image: busybox
    labels:
      kompose.cronjob.backoff_limit: 3
```

### kompose.cronjob.concurrency_policy

```yaml
services:
  periodic-task:
    image: busybox
    labels:
      kompose.cronjob.concurrency_policy: Forbid
```

### kompose.cronjob.schedule

```yaml
services:
  cron-job:
    image: busybox
    labels:
      kompose.cronjob.schedule: "*/5 * * * *"
```

### kompose.hpa.cpu

```yaml
services:
  web:
    image: nginx
    labels:
      kompose.hpa.cpu: 80
```

### kompose.hpa.memory

```yaml
services:
  db:
    image: mysql
    labels:
      kompose.hpa.memory: 512Mi
```

### kompose.hpa.replicas.max

```yaml
services:
  api:
    image: custom-api
    labels:
      kompose.hpa.replicas.max: 10
```

### kompose.hpa.replicas.min

```yaml
services:
  api:
    image: custom-api
    labels:
      kompose.hpa.replicas.min: 2
```

### kompose.image-pull-policy

```yaml
services:
  example-service:
    image: example-image
    labels:
      kompose.image-pull-policy: "IfNotPresent"
```

### kompose.image-pull-secret

```yaml
services:
  private-service:
    image: private-repo/image:tag
    labels:
      kompose.image-pull-secret: "my-private-registry-key"
```

### kompose.init.containers.command

```yaml
services:
  init-service:
    image: busybox
    labels:
      kompose.init.containers.command: ["echo", "Initializing..."]
```

### kompose.init.containers.image

```yaml
services:
  init-service:
    image: busybox
    labels:
      kompose.init.containers.image: busybox
```

### kompose.init.containers.name

```yaml
services:
  init-service:
    image: busybox
    labels:
      kompose.init.containers.name: "initial-setup"
```

### kompose.security-context.fsgroup

```yaml
services:
  secured-service:
    image: nginx
    labels:
      kompose.security-context.fsgroup: 2000
```

### kompose.service.external-traffic-policy

```yaml
services:
  front-end:
    image: quay.io/kompose/web
    ports:
      - 8080:8080
    labels:
      kompose.service.external-traffic-policy: local
```

### kompose.service.expose

```yaml
services:
  web-app:
    image: nginx
    ports:
      - 80:80
    labels:
      kompose.service.expose: "example.com"
```

### kompose.service.expose.ingress-class-name

```yaml
services:
  web:
    image: nginx
    ports:
      - 80:80
    labels:
      kompose.service.expose.ingress-class-name: "nginx"
```

### kompose.service.expose.tls-secret

```yaml
services:
  web:
    image: nginx
    ports:
      - 443:443
    labels:
      kompose.service.expose.tls-secret: "my-ssl-secret"
```

### kompose.service.group

```yaml
version: "3"

services:
  nginx:
    image: nginx
    depends_on:
      - logs
    labels:
      - kompose.service.group=sidecar

  logs:
    image: busybox
    command: ["tail -f /var/log/nginx/access.log"]
    labels:
      - kompose.service.group=sidecar
```

### kompose.service.healthcheck.liveness.http_get_path

```yaml
services:
  web:
    image: custom-web
    ports:
      - "8080:8080"
    labels:
      kompose.service.healthcheck.liveness.http_get_path: /health
```

### kompose.service.healthcheck.liveness.http_get_port

```yaml
services:
  web:
    image: custom-web
    ports:
      - "8080:8080"
    labels:
      kompose.service.healthcheck.liveness.http_get_port: 8080
```

### kompose.service.healthcheck.liveness.tcp_port

```yaml
services:
  db:
    image: mysql
    ports:
      - "3306:3306"
    labels:
      kompose.service.healthcheck.liveness.tcp_port: 3306
```

### kompose.service.healthcheck.readiness.disable

```yaml
services:
  web:
    image: custom-web
    labels:
      kompose.service.healthcheck.readiness.disable: true
```

### kompose.service.healthcheck.readiness.http_get_path

```yaml
services:
  web:
    image: custom-web
    labels:
      kompose.service.healthcheck.readiness.http_get_path: /ready
```

### kompose.service.healthcheck.readiness.http_get_port

```yaml
services:
  web:
    image: custom-web
    labels:
      kompose.service.healthcheck.readiness.http_get_port: 8081
```

### kompose.service.healthcheck.readiness.interval

```yaml
services:
  web:
    image: custom-web
    labels:
      kompose.service.healthcheck.readiness.interval: 10s
```

### kompose.service.healthcheck.readiness.retries

```yaml
services:
  web:
    image: custom-web
    labels:
      kompose.service.healthcheck.readiness.retries: 3
```

### kompose.service.healthcheck.readiness.start_period

```yaml
services:
  web:
    image: custom-web
    labels:
      kompose.service.healthcheck.readiness.start_period: 30s
```

### kompose.service.healthcheck.readiness.tcp_port

```yaml
services:
  db:
    image: mysql
    labels:
      kompose.service.healthcheck.readiness.tcp_port: 3307
```

### kompose.service.healthcheck.readiness.test

```yaml
services:
  web:
    image: custom-web
    labels:
      kompose.service.healthcheck.readiness.test: ["CMD", "curl", "-f", "http://localhost:8081/ready"]
```

### kompose.service.healthcheck.readiness.timeout

```yaml
services:
  web:
    image: custom-web
    labels:
      kompose.service.healthcheck.readiness.timeout: 5s
```

### kompose.service.nodeport.port

```yaml
services:
  web:
    image: nginx
    ports:
      - "30000:80"
    labels:
      kompose.service.nodeport.port: 30000
```

### kompose.service.type

```yaml
services:
  web:
    image: nginx
    ports:
      - "80:80"
    labels:
      kompose.service.type: nodeport
```

### kompose.volume.size

```yaml
services:
  db:
    image: postgres:10.1
    labels:
      kompose.volume.size: 1Gi
    volumes:
      - db-data:/var/lib/postgresql/data
```

### kompose.volume.storage-class-name

```yaml
services:
  db:
    image: postgres:10.1
    labels:
      kompose.volume.storage-class-name: custom-storage-class-name
    volumes:
      - db-data:/var/lib/postgresql/data
```

### kompose.volume.subpath

```yaml
services:
  pgadmin:
    image: postgres
    labels:
      kompose.volume.subpath: pg-data
```

### kompose.volume.type

```yaml
services:
  db:
    image: postgres
    labels:
      kompose.volume.type: persistentVolumeClaim
    volumes:
      - db-data:/var/lib/postgresql/data
```

## Restart Policy

If you want to create normal pods without a controller you can use the `restart` construct of compose to define that. Follow the table below to see what happens on the `restart` value.

| `compose` `restart` | object created    | Pod `restartPolicy` |
|---------------------|-------------------|---------------------|
| `""`                | controller object | `Always`            |
| `always`            | controller object | `Always`            |
| `unless-stopped`    | controller object | `Always`            |
| `on-failure`        | Pod / CronJob     | `OnFailure`         |
| `no`                | Pod / CronJob     | `Never`             |

**Note**: controller object could be `deployment`, `replicationcontroller`, etc.

For example, the `pival` service will become a pod down here. This container calculated the value of `pi`.

```yaml
version: '2'

services:
  pival:
    image: perl
    command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
    restart: "on-failure"
```

For example, the `pival` service will become a cron job down here. This container calculated the value of `pi` every minute.

```yaml
version: '2'

services:
  pival:
    image: perl
    command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
    restart: "no"
    labels:
      kompose.cronjob.schedule: "* * * * *"
      kompose.cronjob.concurrency_policy: "Forbid"
      kompose.cronjob.backoff_limit: "0"
```

#### Warning about Deployment Configs

If the Compose file has a volume specified for a service, the Deployment (Kubernetes) or DeploymentConfig (OpenShift) strategy is changed to "Recreate" instead of "RollingUpdate" (default). This is done to avoid multiple instances of a service from accessing a volume at the same time.

If the Compose file has a service name with `_` or `.` in it (e.g., `web_service` or `web.service`), then it will be replaced by `-` and the service name will be renamed accordingly (e.g., `web-service`). Kompose does this because "Kubernetes" doesn't allow `_` in object names.

Please note that changing the service name might break some `compose` files.

## Building and Pushing Images

If the Compose file has `build` or `build:context, build:dockerfile` keys, build will run when `--build` specified.

And Image will push to _docker.io_ (default) when `--push-image=true` specified.

It is possible to push to a custom registry by specifying `--push-image-registry`, which will override the registry from the image name.

### Authentication on Registry

Kompose uses the docker authentication from file `$DOCKER_CONFIG/config.json`, `$HOME/.docker/config.json`, and `$HOME/.dockercfg` after `docker login`.

**This only works fine on Linux but macOS would fail when using `"credsStore": "osxkeychain"`.**

However, there is an approach to push successfully on macOS, by not using `osxkeychain` for `credsStore`. To disable `osxkeychain`:

- remove `credsStore` from the `config.json` file, and `docker login` again.
- for some docker desktop versions, there is a setting `Securely store Docker logins in macOS keychain`, which should be unchecked. Then restart docker desktop if needed, and `docker login` again.

Now `config.json` should contain base64 encoded passwords, then push image should succeed. Working, but not safe though! Use it at your risk.

For Windows, there is also `credsStore` which is `wincred`. Technically it will fail on authentication as macOS does, but you can try the approach above like macOS too.

### Custom Build and Push

If you want to customize the build and push processes and use another containers solution than Docker,
Kompose offers you the possibility to do that. You can use `--build-command` and `--push-command` flags
to achieve that.

e.g: `kompose -f convert --build-command 'whatever command --you-use' --push-command 'whatever command --you-use'`
