Install Kong Gateway in read-only mode using Docker Compose

Uses: Kong Gateway
Incompatible with
konnect
Related Documentation
Tags
Minimum Version
Kong Gateway - 3.2
TL;DR

Run a Kong Gateway Docker container in DB-less mode using the provided Docker Compose file with read_only set to true.

Prerequisites

This guide requires Docker installed on your system.

Create a kong.yml configuration file

For read-only mode, you need to run Kong Gateway as a DB-less deployment - that is, without a database. This means that you can’t use the Admin API or decK to configure the Gateway instance. Instead, you have to pass a declarative configuration file to Kong Gateway while starting the instance.

Create a directory for your Kong configuration:

mkdir declarative

Then, create a kong.yml file with your entire Gateway configuration. For example, the following file creates a Service and a Route:

cat <<EOF > ./declarative/kong.yml
_format_version: "3.0"
services:
- name: example-service
  url: http://httpbin.org
  routes:
  - name: example-route
    paths:
    - /anything
    protocols:
    - http
    - https
EOF

Set up the Docker Compose file for read-only mode

Now we need to configure our Kong Gateway Docker Compose stack.

In this configuration file, we’re going to mount a Docker volume to the locations where Kong Gateway needs to write data, which includes the /declarative directory. This default configuration requires write access to /tmp and to the prefix path.

Run the following command to create a Docker Compose file at docker-compose.yml with read_only set to true, replacing 3.15.0.5 with your own version of Kong Gateway:

cat <<EOF > docker-compose.yml

services:
  kong-dbless:
    image: '${GW_IMAGE:-kong/kong-gateway:3.15.0.5}' # Kong Gateway image (default to latest version)
    container_name: kong-dbless-readonly
    read_only: true
    restart: unless-stopped
    networks:
      - kong-net
    volumes:
      - ./declarative:/kong/declarative/
      - ./tmp_volume:/tmp
      - ./prefix_volume:/var/run/kong
    environment:
      KONG_PREFIX: /var/run/kong
      KONG_DATABASE: off
      KONG_DECLARATIVE_CONFIG: /kong/declarative/kong.yml
      KONG_PROXY_ACCESS_LOG: /dev/stdout
      KONG_ADMIN_ACCESS_LOG: /dev/stdout
      KONG_PROXY_ERROR_LOG: /dev/stderr
      KONG_ADMIN_ERROR_LOG: /dev/stderr
      KONG_ADMIN_LISTEN: 0.0.0.0:8001
      KONG_ADMIN_GUI_URL: http://localhost:8002
      KONG_LICENSE_DATA: "\${KONG_LICENSE_DATA}" # Kong Enterprise license passed via environment variable
    ports:
      - "8000:8000"
      - "8443:8443"
      - "8001:8001"
      - "8444:8444"
      - "8002:8002"
      - "8445:8445"
      - "8003:8003"
      - "8004:8004"

networks:
  kong-net:
    external: true
EOF

This Docker Compose file will create a read-only Kong Gateway instance without a datastore.

Running in a hardened container

Kong Gateway needs writable volumes mounted at /tmp and at the prefix (KONG_PREFIX) directory, even in a read-only root filesystem. The prefix directory holds the PID file, Unix sockets, the LMDB cache, and the generated NGINX configuration. You can redirect logs, such as proxy_error_log, to a separate writable path or to stderr.

To run as a non-root user, set nginx_user (or the KONG_NGINX_USER environment variable). A non-root user can’t bind to privileged ports (1024 or lower), so configure the proxy and Admin API listeners on ports above 1024.

Start Kong Gateway

Start Kong Gateway with the Docker Compose file:

docker compose up -d

Validate

Let’s make sure that Kong Gateway is running in read-only mode by checking that we can’t write to the API.

First, check that Kong Gateway is running:

curl -X GET "http://localhost:8001/services" \
     --no-progress-meter --fail-with-body 

This will return an HTTP/1.1 200 OK response with the example-service Service configured through kong.yml.

Now, try writing to the Kong Admin API:

curl -X POST "http://localhost:8001/consumers" \
     --no-progress-meter --fail-with-body  \
     -H "Accept: application/json" \
     --json '{
       "username": "consumer"
     }'

This time, you’ll get a 405 Not Allowed response, with the following message:

{"code":12,"message":"cannot create 'consumers' entities when not using a database","name":"operation unsupported"}%

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!