How can I set a static IP address in a Docker container?

99,383

Solution 1

I have already answered this here https://stackoverflow.com/a/35359185/4094678 but I see now that this question is actually older then the aforementioned one, so I'll copy the answer as well:

Easy with Docker version 1.10.1, build 9e83765.

First you need to create you own docker network (mynet123)

docker network create --subnet=172.18.0.0/16 mynet123

than simply run the image (I'll take ubuntu as example)

docker run --net mynet123 --ip 172.18.0.22 -it ubuntu bash

then in ubuntu shell

ip addr

Additionally you could use
--hostname to specify a hostname
--add-host to add more entries to /etc/hosts

Docs (and why you need to create a network) at https://docs.docker.com/engine/reference/commandline/network_create/

Solution 2

I'm using the method written here from the official Docker documentation and I have confirmed it works:

# At one shell, start a container and
# leave its shell idle and running

$ sudo docker run -i -t --rm --net=none base /bin/bash
root@63f36fc01b5f:/#

# At another shell, learn the container process ID
# and create its namespace entry in /var/run/netns/
# for the "ip netns" command we will be using below

$ sudo docker inspect -f '{{.State.Pid}}' 63f36fc01b5f
2778
$ pid=2778
$ sudo mkdir -p /var/run/netns
$ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid

# Check the bridge's IP address and netmask

$ ip addr show docker0
21: docker0: ...
inet 172.17.42.1/16 scope global docker0
...

# Create a pair of "peer" interfaces A and B,
# bind the A end to the bridge, and bring it up

$ sudo ip link add A type veth peer name B
$ sudo brctl addif docker0 A
$ sudo ip link set A up

# Place B inside the container's network namespace,
# rename to eth0, and activate it with a free IP

$ sudo ip link set B netns $pid
$ sudo ip netns exec $pid ip link set dev B name eth0
$ sudo ip netns exec $pid ip link set eth0 up
$ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0
$ sudo ip netns exec $pid ip route add default via 172.17.42.1

Using this approach I run my containers always with net=none and set IP addresses with an external script.

Solution 3

Actually, despite my initial failure, @MarkO'Connor's answer was correct. I created a new interface (docker0) in my host /etc/network/interfaces file, ran sudo ifup docker0 on the host, and then ran

docker run --net=host -i -t ... 

which picked up the static IP and assigned it to docker0 in the container.

Thanks!

Solution 4

This worked for me:

docker run --cap-add=NET_ADMIN -d -it myimages/image1  /bin/sh -c "/sbin/ip addr add 172.17.0.8 dev eth0;  bash"

Explained:

  • --cap-add=NET_ADMIN have rights for administering the net (i.e. for the /sbin/ip command)

  • myimages/image1 image for the container

  • /bin/sh -c "/sbin/ip addr add 172.17.0.8 dev eth0 ; bash" Inside the container run ip addr add 172.17.0.8 dev eth0 to add a new ip address 172.17.0.8 to this container (caution: do use a free ip address now and in the future). Then run bash, just to not have the container automatically stopped.

Bonus:

My target scene: setup a distributed app with containers playing different roles in the dist-app. A "conductor container" is able to run docker commands by itself (inside) so to start and stop containers as needed. Each container is configured to know where to connect to access a particular role/container in the dist-app (so the set of ip's for each role must be known by each partner).

To do this:

  1. "conductor container"

image created with this Dockerfile

FROM pin3da/docker-zeromq-node
MAINTAINER Foobar

# install docker software  
RUN apt-get -yqq update && apt-get -yqq install docker.io 

# export /var/run/docker.sock  so we can connect it in the host
VOLUME /var/run/docker.sock

image build command:

docker build --tag=myimages/conductor --file=Dockerfile .

container run command:

docker run -v /var/run/docker.sock:/var/run/docker.sock --name=conductor1 -d -it myimages/conductor  bash
  1. Run containers with different roles.

First (not absolutely necessary) add entries to /etc/hosts to locate partners by ip or name (option --add-host)

Second (obviously required) assign a ip to the running container (use /sbin/ip in it)

docker run --cap-add=NET_ADMIN --add-host worker1:172.17.0.8 --add-host worker2:172.17.0.9 --name=worker1 -h worker1.example.com -d -it myimages/image1  /bin/sh -c "/sbin/ip addr add 172.17.0.8 dev eth0;  bash"

Solution 5

Docker containers by default do not have sufficient privileges to manipulate the network stack. You can try adding --cap-add=NET_ADMIN to the run command to allow this specific capability. Or you can try --privileged=true (grants all rights) for testing.

Another option is to use pipework from the host.

Share:
99,383

Related videos on Youtube

dlanced
Author by

dlanced

Updated on November 30, 2020

Comments

  • dlanced
    dlanced over 3 years

    I'm perfectly happy with the IP range that docker is giving me by default 176.17.x.x, so I don't need to create a new bridge, I just want to give my containers a static address within that range so I can point client browsers to it directly. I tried using

    RUN echo "auto eth0" >> /etc/network/interfaces
    RUN echo "iface eth0 inet static" >> /etc/network/interfaces
    RUN echo "address 176.17.0.250" >> /etc/network/interfaces
    RUN echo "netmask 255.255.0.0" >> /etc/network/interfaces
    RUN ifdown eth0
    RUN ifup eth0
    

    from a Dockerfile, and it properly populated the interfaces file, but the interface itself didn't change. In fact, running ifup eth0 within the container gets this error:

    RTNETLINK answers: Operation not permitted Failed to bring up eth0

    • Mark O'Connor
      Mark O'Connor over 9 years
      You could try using the --net=host option. The container will then be available on the host's IP address.
    • dlanced
      dlanced over 9 years
      Thanks Mark. I re-wrote the Dockerfile to set an interface called docker0 (which is what --net=host will create) with my static IP, built the image and loaded it using --net=host. But docker0 still gets its IP from DHCP and ifup docker0 still doesn't work.
    • Matt
      Matt over 6 years
      Possible duplicate of Assign static IP to Docker container
  • Kryten
    Kryten over 9 years
    Just trying this suggestion, but I've run into a problem: setting --net=none seems to make it impossible to --link containers. Is this correct?
  • unlink
    unlink over 9 years
    Sorry, I never used the --link commands (because my containers don't talk each other)
  • Kryten
    Kryten over 9 years
    No prob. After I posted the comment, I thought about it more and it makes sense that it wouldn't work. But it also makes sense that you can configure multiple containers to communicate with one another by the method you've shown. This seems to be the approach of pipework (which I am now attempting to use)
  • sourcejedi
    sourcejedi over 8 years
    Explain static IP with Weave? Can't find it in the docs (not that that would be an excuse not to explain the answer properly).
  • errordeveloper
    errordeveloper over 8 years
    You can start a container with -e WEAVE_CIDR=ip:192.168.1.2/24, and given you have Weave Net running along with proxy environment setup in your shell (weave launch; eval $(weave env)), that container should get the IP address you have specified.
  • Michael Z
    Michael Z over 7 years
    I got Object "netns" is unknown, try "ip help".