Could somebody please help me with this Docker Compose file?

I have these commands that I want to use in a docker compose file, and I suck at YAML.

FROM signalk/signalk-server
USER root

docker build -t signalk-server . 
docker run --init -it --rm --name signalk-server  --env PORT=80 --network host --entrypoint /home/node/signalk/bin/signalk-server test

In addition I have devices and volumes. From Dockerize I pieced together this, which isn’t working:

name: SignalK
services:
    signalk-server:
        init: true
        stdin_open: true
        tty: true
        container_name: signalk-server
        environment:
            - PORT=80
        network_mode: host
        entrypoint:
            - /home/node/signalk/bin/signalk-server
        image: signalk-server
    restart: no
    group_add:
        - "20"

    devices:
      - /media/pi/Docker/Docker-Compose/SignalK/sailorhat-usb-0:/dev/ttyUSB0 #Sailor Hat
      - /media/pi/Docker/Docker-Compose/SignalK/garmin-usb-0:/dev/ttyUSB1 #Garmin
    volumes:
      - /dev:/dev
      - /media/pi/Docker/Docker-Compose/SignalK/SignalK-data:/home/node/.signalk
    entrypoint: sh /home/node/signalk/startup.sh
    privileged: true
    logging:
      options:
        max-size: 10m

That says

services.restart must be a mapping

I have tried moving the lines around, but it only gives me new errors. It may be an indentation or something simple like that, or it may be that I got it all totally wrong. Not to mention that I haven’t found out how to use the “from” and “user root” correctly. Does somebody have the time to help me? I hope this is simple for somebody who knows what they’re doing, which I dont… :flushed:

You can convert every docker run command to a compose file with Composerize and the other way around with Decomposerize.

name: SignalK
services:
    signalk-server:
        init: true
        stdin_open: true
        tty: true
        container_name: signalk-server
        environment:
            - PORT=80
        network_mode: host
        entrypoint:
            - /home/node/signalk/bin/signalk-server
        image: signalk-server
        restart: no
        group_add:
            - "20"
        devices:
          - /media/pi/Docker/Docker-Compose/SignalK/sailorhat-usb-0:/dev/ttyUSB0 #Sailor Hat
          - /media/pi/Docker/Docker-Compose/SignalK/garmin-usb-0:/dev/ttyUSB1 #Garmin
        volumes:
          - /dev:/dev
          - /media/pi/Docker/Docker-Compose/SignalK/SignalK-data:/home/node/.signalk
        entrypoint: sh /home/node/signalk/startup.sh
        privileged: true
        logging:
          options:
            max-size: 10m

Update. I forget to mention, that it indeed seems to be just an indentation problem.

1 Like

Thanks for answering! That’s what I tried, but I couldn’t get it working. And I suspected indentation, thanks! I get as far as trying to pull now, but that gives me the error:

 ✘ signalk-server Error pull access denied for si...                       1.6s 
Error response from daemon: pull access denied for signalk-server, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

The first commands in the message, can they be the problem? Can you tell me how I implement them?

FROM signalk/signalk-server
USER root

I assume building a custom image is unrelated to the compose file (as it doesn’t have a build key)?

Probably it didn’t like that you didn’t provide a tag. We usually use stable version tags, instead of the latest, to ensure repeatable builds.

FROM signalk/signalk-server:v2.8.3
USER root

update: My bad. Missed that it was already part of the first post. I just skimmed the compose file and saw the indentation errors.

No problem, I’m happy as long as I get help. :grin:

And I was hoping that I could build in the compose file, like I have installed stuff in another file, but that’s not possible, then? It’s to get port 80 working as the GUI port (I have it over the web as well, so it creates problems using other ports). You may remember that you said that was possible, but the developer says:

But I think I am starting to understand a bit more now. I have read about Dockerfiles, and I see that they are instructions for the build. So where whould I put that dockerfile? Do I need to find out where the images are pulled to?

Well you can:

If you have the Dockerfile in the same folder as the compose file:

name: SignalK
services:
    signalk-server:
        build:
            context: .
        ...

If you want to use embed the Dockerfile content inline:

name: SignalK
services:
    signalk-server:
        build:
            context: .
            dockerfile_inline: |
                FROM signalk/signalk-server:v2.8.3
                USER root
        ...

It will only build the image, if it doesn’t exist yet. If it exists you can do docker compose build or docker compose --build up.

1 Like

I just tested it:

# network = default bridge
me@docker:~$  docker run -it --rm -u 111111 -p 80:80 python python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
^C
Keyboard interrupt received, exiting.
me@docker:~$ docker run -it --rm -u 111111 --network host python python3 -m http.server 80
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/usr/local/lib/python3.12/http/server.py", line 1314, in <module>
    test(
  File "/usr/local/lib/python3.12/http/server.py", line 1261, in test
    with ServerClass(addr, HandlerClass) as httpd:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/socketserver.py", line 457, in __init__
    self.server_bind()
  File "/usr/local/lib/python3.12/http/server.py", line 1308, in server_bind
    return super().server_bind()
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/http/server.py", line 136, in server_bind
    socketserver.TCPServer.server_bind(self)
  File "/usr/local/lib/python3.12/socketserver.py", line 473, in server_bind
    self.socket.bind(self.server_address)
PermissionError: [Errno 13] Permission denied

So apparently he is right when --network host is used. Which would make sense, as the contaiener joins the network namespace of the host, and therefor all restricts on network level also apply for the container.

Well, then that ends that debate, I guess. :grin:

But now I’m up and running on port 80! Thank you very much for your help! This is the final Docker Compose file, in case I should happen to delete it without having a backup (unlikely with my compulsive backup habits, but still…):

name: SignalK
services:
    signalk-server:
        build:
            context: .
            dockerfile_inline: |
                FROM signalk/signalk-server
                USER root
        init: true
        stdin_open: true
        tty: true
        container_name: signalk-server
        environment:
            - PORT=80
        network_mode: host
        entrypoint:
            - /home/node/signalk/bin/signalk-server
        image: signalk/signalk-server
        restart: no
        user: root
        group_add:
            - "20"
        devices:
          - /media/pi/Docker/Docker-Compose/SignalK/sailorhat-usb-0:/dev/ttyUSB0 #Sailor Hat
          - /media/pi/Docker/Docker-Compose/SignalK/garmin-usb-0:/dev/ttyUSB1 #Garmin
        volumes:
          - /dev:/dev
          - /media/pi/Docker/Docker-Compose/SignalK/SignalK-data:/root/.signalk
        privileged: true
        logging:
          options:
            max-size: 10m

May I ask why you’re building an image practically identical to the one you’re pulling from?

Running the signalk/signalk-server image, the root user is already the default one used

What am I missing?

You may certainly ask, and the answer is that you are mistaken (at least according to the developers of SignalK and I would assume they know what they are talking about). The node user is the default one used, and I am building an image running the root user to finally expose port 80 in host network mode.

I see, I have not looked at documentation, I simply ran the following:

docker run --name signalk signalk/signalk-server
docker exec -it signalk /bin/bash

And saw I was root…

My apologies, it was my own misunderstanding
Running docker exec -it signal whoami returns node indeed

So I guess /bin/bash will always be in root?

I think so, but I’m not sure. I just follow instructions when people are kind enough to give me some. :rofl:

Nah. You got a point there.

# start container as {value of USER instruction}
me@docker :~$ docker run -d --rm --name signalk signalk/signalk-server
5751e5315e66e086fe65458f953fbbe9437d5e5e7117706564561ae8503d4da6
me@docker:~$  docker exec -ti signalk whoami
node

# start container as root
me@docker:~$ docker run -d --rm --name signalk -u 0 signalk/signalk-server
8a9f8d83a843bbf77c248900fe7dd6566084b5d1c43c53689d994a60e30c0a4d
me@docker:~$ docker exec -ti signalk whoami
root

So probably the user: root configuration in the compose file would have sufficient already.