How to get docker mapped ports from node.js application?

前端 未结 4 682
無奈伤痛
無奈伤痛 2021-02-06 05:44

I would like to get mapped port from inside node.js application.

ex.

docker-compose:

my-app:
    build:
        context: ./my-app
           


        
4条回答
  •  我在风中等你
    2021-02-06 05:55

    So the first thing is that currently, docker doesn't give the metadata information inside the container in any direct manner. There are workarounds to the same though

    Now passing a docker socket inside your container is something that you can live with when it concerns a development environment but not prod environment

    So what you want to do is build your own metadata service and then let it give the information back to your container without exposing the docker socket itself.

    Now to get this metadata you can use two approaches

    Metadata service based on container id

    In this case, you create a simple endpoint like /metadata/container_id and then return the data you want.

    This service can run on the main host itself or on the container which has the docker socket mapped.

    Now in your NodeJS service, you will get the current container ID and then use the same to call this service. This can be done in different ways as listed in below thread

    Docker, how to get container information from within the container?

    The data returned you can restrict, in case I only want ports to be exposed, I will only return the detail of the ports only.

    The problem with this approach is that you are still letting the service figure out its own container id and also at the same time trusting that it is sending the correct container id

    Metadata service without passing any information

    To get metadata information without passing information, we need to identify which pad made a call to the metadata server

    This can be identified by using the source IP. Then we need to identify which container belongs to this IP. Once we have the container ID, we can return the metadata.

    Below is a simple bash script that does the same

    #!/bin/bash
    CONTAINER_IP=$SOCAT_PEERADDR
    CONTAINER_ID=$(docker ps -q | xargs docker inspect -f '{{.Id}}|{{range .NetworkSettings.Networks}}{{.IPAddress}}|{{end}}' | grep "|$CONTAINER_IP|" | cut -d '|' -f 1)
    echo -e "HTTP/1.1 200 OK\r\nContent-Type: application/json;\r\nServer: $SOCAT_SOCKADDR:$SOCAT_SOCKPORT\r\nClient: $SOCAT_PEERADDR:$SOCAT_PEERPORT\r\nConnection: close\r\n";
    METADATA=$(docker inspect -f '{{ json .NetworkSettings.Ports }}' $CONTAINER_ID)
    echo $METADATA
    

    Now to convert this to a web server we can use socat.

    sudo socat -T 1 TCP-L:10081,pktinfo,reuseaddr,fork EXEC:./return_metadata.sh
    

    Now inside the container when we call this metadata server

    root@a9cf6dabdfb4:/# curl 192.168.33.100:10081
    {"80/tcp":[{"HostIp":"0.0.0.0","HostPort":"8080"}]}
    

    and the docker ps for the same

    CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                  NAMES
    a9cf6dabdfb4        nginx                 "nginx -g 'daemon of…"   3 hours ago         Up 3 hours          0.0.0.0:8080->80/tcp   nginx
    

    Now how you create such a metadata server is upto you. You can use any approach

    • socat approach I showed
    • build one in nodejs
    • build one using https://github.com/avleen/bashttpd
    • build one using openresty

    You can also add the IP of the service using extra_hosts in your docker-compose.yml and make the call like curl metaserver:10081

    This should be a decently secure approach, without compromising on what you need

提交回复
热议问题