Bash Docker container innerhalb eines docker containers starten - geht das?

CyborgBeta

Captain
Registriert
Jan. 2021
Beiträge
3.318
Hallo, vielleicht hat hier jemand eine Idee, mich hat das schon die halbe Nacht gekostet ...

Ich nutze traefik mit einer docker-compose.yml mit Services, und möchte darin discourse starten.

Aus der docker-compose.yml:

Code:
  forum:
    build: ./forum
    #privileged: true # for child container
    stop_signal: SIGINT
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock # for sibling container
      - ./forum/discourse/:/var/discourse/
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.forum.rule=Host(`forum.irgendetwas.com`)"
      - "traefik.http.services.forum.loadbalancer.servers.url=http://app:80"
      - "traefik.http.routers.forum.entrypoints=websecure"
      - "traefik.http.routers.forum.tls.certresolver=myresolver"

Aus dem forum/Dockerfile:

Code:
FROM debian:12

ENV TZ=Europe/Berlin

RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

RUN apt update
RUN apt upgrade -y
RUN apt install git docker.io net-tools -y
#RUN /var/discourse/launcher rebuild app

CMD [ "sh", "-c", "/var/discourse/launcher rebuild app \
&& trap '/var/discourse/launcher stop app; exit' INT; echo waiting; while : ; do sleep 1 ; done" ]

Aus der forum/discourse/containers/app.yml:

Code:
## this is the all-in-one, standalone Discourse Docker container template
##
## After making changes to this file, you MUST rebuild
## /var/discourse/launcher rebuild app
##
## BE *VERY* CAREFUL WHEN EDITING!
## YAML FILES ARE SUPER SUPER SENSITIVE TO MISTAKES IN WHITESPACE OR ALIGNMENT!
## visit http://www.yamllint.com/ to validate this file as needed

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  ## Uncomment the next line to enable the IPv6 listener
  #- "templates/web.ipv6.template.yml"
  - "templates/web.ratelimited.template.yml"
  ## Uncomment these two lines if you wish to add Lets Encrypt (https)
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"
  #- "templates/web.socketed.template.yml"

## which TCP/IP ports should this container expose?
## If you want Discourse to share a port with another webserver like Apache or nginx,
## see https://meta.discourse.org/t/17247 for details
#expose:
#  - "80:80"   # http
#  - "443:443"  # https

params:
  db_default_text_search_config: "pg_catalog.english"

  ## Set db_shared_buffers to a max of 25% of the total memory.
  ## will be set automatically by bootstrap based on detected RAM, or you can override
  #db_shared_buffers: "256MB"

  ## can improve sorting performance, but adds memory usage per-connection
  #db_work_mem: "40MB"

  ## Which Git revision should this container use? (default: tests-passed)
  #version: tests-passed

env:
  LC_ALL: en_US.UTF-8
  LANG: en_US.UTF-8
  LANGUAGE: en_US.UTF-8
  # DISCOURSE_DEFAULT_LOCALE: en

  # FORCE SSL 
  DISCOURSE_FORCE_HTTPS: true

  ## How many concurrent web requests are supported? Depends on memory and CPU cores.
  ## will be set automatically by bootstrap based on detected CPUs, or you can override
  #UNICORN_WORKERS: 3

  ## TODO: The domain name this Discourse instance will respond to
  ## Required. Discourse will not work with a bare IP number.
  DISCOURSE_HOSTNAME: forum.irgendetwas.com

  ## Uncomment if you want the container to be started with the same
  ## hostname (-h option) as specified above (default "$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

So weit, so gut. Ich kann das Teil starten mit docker compose up -d. Daraufhin wird dann discourse gebaut (ca. 2 Minuten), und es wird ein sibling container names app gestartet:

Code:
docker ps
CONTAINER ID   IMAGE                                                COMMAND                  CREATED          STATUS          PORTS                                                                                                                                                                                                                                                                      NAMES
ebd29111340c   local_discourse/app                                  "/sbin/boot"             28 minutes ago   Up 28 minutes                                                                                                                                                                                                                                                                              app
07983cdec0e3   proxy-forum                                          "sh -c '/var/discour…"   35 minutes ago   Up 35 minutes                                                                                                                                                                                                                                                                              proxy-forum-1

app öffnet intern zwei Ports, einmal 3000 für discourse und einmal 80 für nginx (an der Stelle verstehe ich nicht, wieso noch einmal ein zweiter reverse proxy neben traefik benötigt wird ...):

Code:
docker inspect app | grep Name
        "Name": "/app",
                "Name": "always",
            "Name": "overlay2"
                    "DNSNames": null

Code:
docker inspect app | grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2",

Allerdings komme ich über curl nicht an den container heran:

Code:
curl app:80
curl: (6) Could not resolve host: app

Es muss doch möglich sein, an die IP bzw. den Namen eines anderen Services zu gelangen, ohne dass diese vorher bekannt ist? Ich habe bestimmt irgendetwas Einfaches (beim Hostname oder so) übersehen.

... Da mein Setup von der Standardinstallation abweicht, ist https://meta.discourse.org/t/instal...ing-recommended-supported-installation/300191 hier nur bedingt anwendbar.
 
Die hostnames sind nur innerhalb des Docker Netzwerks gültig, darin befindest du dich auf seitens des hosts ja nicht. Die gängige vorgehensweise ist es hier, den Reverseproxy per Port-Bind über den Host freizugeben, dann kannst du auf dem Host selbst einfach localhost nutzen und auf externen Hosts die IP des Docker-Hosts.

Der nginx wird vermutlich app-interne Dinge wie Assets bereitstellen, je nach Konfiguration könnte man ihn aber vielleicht auch ersetzen. Einzelfall abhängig, da kenne ich mich mit der Applikation nicht aus.
 
  • Gefällt mir
Reaktionen: netzgestaltung und CyborgBeta
Bagbag schrieb:
Die hostnames sind nur innerhalb des Docker Netzwerks gültig, darin befindest du dich auf seitens des hosts ja nicht.
Das stimmt, allerdings müssten diese doch traefik bekannt sein?
 
Sofern dein docker-compose.yml nicht mehr beinhaltet, als das hier gepostete, dann nein, da du beide container in ein Netzwerk stecken musst, sonst kann traefik nicht damit kommunizieren (und auch nicht auflösen).

Wo hast du curl denn aufgerufen? Auf dem Host? Dann bringt es dir auch nix, wenn traefik es kennt, dein Host muss es ja kennen.
 
Bagbag schrieb:
dann kannst du auf dem Host selbst einfach localhost nutzen und auf externen Hosts die IP des Docker-Hosts.
Hab es gerade einmal probiert,

curl 172.17.0.2:80 funktioniert auf dem Host, um zum Container zu gelangen.
 
Die 172.17.0.2 würde ich aber nicht verwenden, da die beim nächsten Container start schon nicht mehr passt. Die vergibt Docker bei jedem Container start neu. Und fix zuweisen würde ich persönlich auch nicht machen. Mal davon abgesehen, dass die von extern sowieso nicht funktioniert.
 
Bagbag schrieb:
Sofern dein docker-compose.yml nicht mehr beinhaltet, als das hier gepostete,

Beinhaltet schon noch etwas mehr ... (sensible Daten habe ich hier durch abcd ersetzt)

Code:
services:

  traefik:
    image: traefik:latest
    container_name: "traefik"
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.email=abcd"
      - "--certificatesresolvers.myresolver.acme.storage=abcd"
    labels:
      - "traefik.enable=true"
      - "abcd..."
    ports:
      - 8180:8080
      - 443:443
    volumes:
      - "./abcd:/letsencrypt"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

Bagbag schrieb:
Die 172.17.0.2 würde ich aber nicht verwenden, da die beim nächsten Container start schon nicht mehr passt. Die vergibt Docker bei jedem Container start neu.
So sehe ich das auch, deshalb meine Frage, wie der sibling container "app" richtigerweise adressiert werden kann (von traefik oder dem Host aus gesehen).
 
Lies dich mal in docker networks ein, die fehlen dir hier.
 
Traefik (oder bzw. Docker) baut da automatisch intern ein Netzwerk auf ...

Ein Teil von docker network inspect proxy_default:

Code:
[
    {
        "Name": "proxy_default",
        "Id": "abcd",
        "Created": "2024-12-16T06:25:24.663849371+01:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "abcd": {
                "Name": "proxy-forum-1",
                "EndpointID": "abcd",
                "MacAddress": "abcd",
                "IPv4Address": "172.18.0.18/16",
                "IPv6Address": ""
            },
usw.
        "Options": {},
        "Labels": {
            "com.docker.compose.config-hash": "abcd",
            "com.docker.compose.network": "default",
            "com.docker.compose.project": "proxy",
            "com.docker.compose.version": "2.31.0"
        }
    }
]

Das Problem wird sein, dass der Service "app" nicht mit in der Container-Liste steht ...
 
Ich hatte bei mir immer ein externes netzwerk "reverseproxy", darin traefik/caddy und die applikationen. Dann kann traefik auf alles nötige zugreifen.

Wenn du mehr isolieren willst, erstellst du für jede Applikation ein Netzwerk und packt traefik mit rein, dann können die Apps nicht untereinander kommunizieren.

traefik ist dann das einzige, dass ein Port-Bind auf den Host braucht. Darüber ist dann alles von außen erreichbar.
 
  • Gefällt mir
Reaktionen: Der Lord und CyborgBeta
Bekomme das nicht hin. Habe jetzt zu jedem Service network_mode: bridge hinzugefügt, und es werden auch alle Services zu bridge hinzugefügt - aber dennoch ist curl app:80 (vom Host und auch innerhalb des Service) nicht auflösbar. 😬
 
Der Host wird nie in der Lage sein, "app" aufzulösen. Das funktioniert nur innerhalb der Docker Netzwerke, da hier der Docker DNS genutzt wird. Außerdem willst du ja auch gar nicht auf "app", sondern auf "traefik", der TLS etc. macht. Und den erreichst du über den Portbind.

ganz grob (mal ohne traefik config etc.):
Code:
docker network create reverseproxy
docker container create --network reverseproxy --port 80:80 traefik
docker container create --network reverseproxy myapp
curl localhost

Das sollte funktionieren. Nur halt bei dir über docker-compose.
 
Also das

1734536787007.png

https://docs.docker.com/engine/network/drivers/bridge/#options

ist für das Standard bridge Netzwerk bereits aktiviert.

Aber ich vermute, dass der Container "app" keinen oder einen anderen Hostname hat.

Ich habe

Code:
  ## Uncomment if you want the container to be started with the same
  ## hostname (-h option) as specified above (default "$hostname-$config")
  DOCKER_USE_HOSTNAME: true

das einfach mal auf true gesetzt und starte noch mal neu. Vielleicht ändert sich gleich etwas.
Ergänzung ()

Gefunden:

1734537680453.png

https://docs.docker.com/engine/network/drivers/bridge/

Ich brauche also doch ein eigenes "user-defined bridge network" ... melde mich gleich noch mal.
 
Zuletzt bearbeitet:
So, kurzes Update: ich geb's auf. Es funktioniert nicht und es kann auch gar nicht funktionieren... Zwar funktioniert curl inzwischen mit dem Namen des Services, nachdem der Service zum proxy Netzwerk hinzugefügt wurde (manuell), aber Traefik verweigert die Weiterleitung zum Service. Dann lasse ich das und verwende fürs Forum einen anderen Server... muss ja nicht alles auf einem laufen.
 
Und das betreibst du dann ohne Reverseproxy?

Hier wird dein Problem ja jetzt wohl nicht Docker, sondern die traefik Konfiguration sein.
 
Bagbag schrieb:
Hier wird dein Problem ja jetzt wohl nicht Docker, sondern die traefik Konfiguration sein.
Nein, es geht schlichtweg nicht. ;)

Bagbag schrieb:
Und das betreibst du dann ohne Reverseproxy?
Nur mit dem Discourse-eigenen, sprich der Standardinstallation.
 
Und warum willst du unter Docker dann traefik davor schalten? Einfach Port-Bind und fertig. Oder hast du noch andere HTTP(s) Dienste auf dem Server?
 
Bagbag schrieb:
Oder hast du noch andere HTTP(s) Dienste auf dem Server?
Ja, ca. 20 :P

Es ist aber nicht so tragisch, ich habe noch einen zweiten, kleineren Server, nur für Discourse.
 
Zurück
Oben