Multiple zrok shares on docker

Hi! I want to have two shares, each from a seperate docker-compose. Each has there own unique name domain and a different target.

I tried to use the same volume where .zrok is stored but then it overwrites the reserved share of the one that started first and changes it's target.

zrok backend is already reserved: stockbrood
zrok-epic-share-1  | INFO: running: zrok share reserved stockbrood --override-endpoint http://host.docker.internal:3000 --headless                                                                                                                                  

I also tried to use a different volume and keep things seperate but then it tries to enable the environment with the same key cause both .env have the same ZROK_ENABLE_TOKEN. I need to enable the environment so that it creates the .zrok folder in the volume but it can't create it cause it can't execute zrok enable twice.

I wonder if it is possible to have seperate state directories of different shares in docker. Currently it fills the state directory with the zrok enable command but this can't be run twice with the same ZROK_ENABLE_TOKEN (I think or at least it gives an error that there was a problem enabling the environment).

[EDIT]
I got it working with customising the zrok-share.bash locally.
I made my reserved.json support multiple reserved shares in one enabled environment.

{
  "shares": [
    {
      "token": "stockbrood",
      "target": "http://host.docker.internal:80",
      "frontend_endpoints": [
        "https://stockbrood.share.zrok.io"
      ]
    }
  ]
}

instead of

{"token":"stockbrood","frontend_endpoints":["https://stockbrood.share.zrok.io"]}

The key logic that checks for existing shares:

EXISTING_SHARES=$(jq -r '.shares[]?.target' ~/.zrok/reserved.json 2>/dev/null)
FOUND_SHARE=false
    
while IFS= read -r target; do
  if [[ "${target}" == "${ZROK_TARGET}" ]]; then
    FOUND_SHARE=true
    ZROK_RESERVED_TOKEN=$(jq -r --arg target "${ZROK_TARGET}" '.shares[] | select(.target == $target) | .token' ~/.zrok/reserved.json)

The part that adds new shares to the array instead of overwriting:

jq --arg token "${NEW_TOKEN}" \
   --arg target "${ZROK_TARGET}" \
   --argjson endpoints "${NEW_ENDPOINTS}" \
   '.shares += [{"token": $token, "target": $target, "frontend_endpoints": $endpoints}]' \
   ~/.zrok/reserved.json

Welcome, @NinoV-2469197. I'm glad you found a good solution. That's tidier than redundant volumes for each share.

FYI: A forthcoming release of zrok has a background "agent" mode that will simplify multiple shares, so we'll be rewriting the Docker share guides soon.

1 Like

It's there some guide how to setup two different services on docker?

I would use it

This is an example: zrok/docker/compose/zrok-public-reserved/compose.override.yml at v1.0.0 · openziti/zrok · GitHub that supplements the main example compose file for a reserved public share: zrok/docker/compose/zrok-public-reserved/compose.yml at v1.0.0 · openziti/zrok · GitHub

Here's what you need to know:

  1. This is an example of two reserved public shares using the same zrok account enabled in a Docker volume zrok_env. This approach is self-contained, not mounted from the Docker host's ~/.zrok, so it manages the zrok environment and reservations through env vars as config (zrok frontdoor | zrok).
  2. If you wish to mount ~/.zrok, then you don't need any of these env vars or wrapper scripts. Instead, run zrok reserve on the Docker host then add as many containers as you want, each running zrok share reserved like this: Getting Started with Docker | zrok

Example of the simplified, mounted environment approach:

Use the enabled zrok environment you will mount on the Docker host to reserve your shares.

zrok reserve public -n "myapp1" http://myapp1:8001
zrok reserve public -n "myapp2" http://myapp2:8002

Then in compose, zrok can reach the servers with Docker DNS.

services:
  myapp1:
    image: myapps/myapp1
    restart: unless-stopped
    expose:
      - 8001
  myapp2:
    image: myapps/myapp1
    restart: unless-stopped
    expose:
      - 8002
  zrok-myapp1:
    image: openziti/zrok
    restart: unless-stopped
    user: "${UID}"
    volumes:
      - ${HOME}/.zrok:/home/ziggy/.zrok
    command: share reserved "myapp1" --headless
  zrok-myapp2:
    image: openziti/zrok
    restart: unless-stopped
    user: "${UID}"
    volumes:
      - ${HOME}/.zrok:/home/ziggy/.zrok
    command: share reserved "myapp2" --headless

1 Like

if I want to share localhost:3000 and loclahost:3080
I need to reserve MyAPP1 localhost:3000 and reserve MyAPP2 localhost:3080

an then put a .env file with:

services:
  myapp1:
    image: myapps/myapp1
    restart: unless-stopped
    expose:
      - 3000
  myapp2:
    image: myapps/myapp1
    restart: unless-stopped
    expose:
      - 3080
  zrok-myapp1:
    image: openziti/zrok
    restart: unless-stopped
    user: "${UID}"
    volumes:
      - ${HOME}/.zrok:/home/ziggy/.zrok
    command: share reserved "myapp1" --headless
  zrok-myapp2:
    image: openziti/zrok
    restart: unless-stopped
    user: "${UID}"
    volumes:
      - ${HOME}/.zrok:/home/ziggy/.zrok
    command: share reserved "myapp2" --headless

and docker compose up with the https://docs.zrok.io/zrok-public-reserved/compose.yml file?

Thanks for your reply

Oh, not .env, my example YAML represents a compose.yml that could stand alone if your servers are also containers, but now it sounds like the server apps are running on the Docker host, not in containers, or at least not in the same Docker network where you wish to run zrok. You don't need another compose file if you're mounting ~/. zrok like this, only if you want a self-contained zrok Docker share environment.

If reserving a proxy target address like 127.0.0.1:3080 (slightly more compatible than "localhost") then you can set network_mode: host to run your zrok share containers on the Docker host interface instead of creating a Docker bridge network for the compose project, which is the default network behavior.

services:
  zrok-myapp1:
    image: openziti/zrok
    restart: unless-stopped
    user: "${UID}"
    volumes:
      - ${HOME}/.zrok:/home/ziggy/.zrok
    network_mode: host
    command: share reserved "myapp1" --headless
  zrok-myapp2:
    image: openziti/zrok
    restart: unless-stopped
    user: "${UID}"
    volumes:
      - ${HOME}/.zrok:/home/ziggy/.zrok
    network_mode: host
    command: share reserved "myapp2" --headless

Reply, yes I use two apps on Docker each one in a Container, one set up port 3000 and another to port 3080 and yes I would put the zrok service. Now I have it configured with one of them, and would run the two of them form there as I have them running along the docker service. Yes I use the ip as it's more convenient. For Myapps I can use zc95c7dty5fo and e6mtrbpytgcs the actual shares and your compose.yml

Thanks a lot

Okay, good luck. BTW, if the server target address ever changes you can keep using the same zrok reservation and override the address by adding to the command like share reserved zc95c7dty5fo --override-endpoint http://new-addresss:9090.

1 Like

Call me dumb What I need to put on :

user: "${UID}"
```?

It's probably already set to a user id number like 1000 so I wouldn't change it unless you have a problem.

1 Like

Thanks for all your help!

1 Like