283

I'm now trying to assign a static IP 172.17.0.1 when a Docker container be started up.

I use port 2122 as the ssh port of this container so that I let this container listen port 2122.

sudo docker run -i -t -p 2122:2122 ubuntu

This command will run a Docker container with a random IP like 172.17.0.5, but I need to assign a specific IP to the container.

The following shell script is what I reference Docker documentation in advanced network settings.

pid=$(sudo docker inspect -f '{{.State.Pid}}' <container_name> 2>/dev/null)
sudo rm -rf /var/run/netns/*
sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid
sudo ip link add A type veth peer name B
sudo brctl addif docker0 A
sudo ip link set A up
sudo ip link set B netns $pid
sudo ip netns exec $pid ip link set eth0 down
sudo ip netns exec $pid ip link delete eth0
sudo ip netns exec $pid ip link set dev B name eth0
sudo ip netns exec $pid ip link set eth0 address 12:34:56:78:9a:bc
sudo ip netns exec $pid ip link set eth0 down
sudo ip netns exec $pid ip link set eth0 up
sudo ip netns exec $pid ip addr add 172.17.0.1/16 dev eth0
sudo ip netns exec $pid ip route add default via 172.17.42.1

This shell script will assign a static IP 172.17.0.1 and link to the world fine. But whenever I try to ssh to this container from my local, it didn't work. What's the problem possibly I met?

Vini.g.fer
  • 11,639
  • 16
  • 61
  • 90
LarryLo
  • 2,923
  • 3
  • 12
  • 11
  • I am afraid there is not a simple answer to that question, see https://github.com/docker/docker/issues/6743 and https://github.com/docker/docker/issues/1179, and read https://github.com/jpetazzo/pipework – user2915097 Jan 14 '15 at 07:28
  • @larrylo can you confirm that you started an sshd inside the container? – Bryan Jan 14 '15 at 10:30
  • 5
    You are undoing all the routing that the docker daemon does for you. Containers are not VMs. – user2105103 Jan 14 '15 at 14:25
  • Yes, I confirm I can start sshd inside the container – LarryLo Jan 15 '15 at 03:44
  • @user2105103 How I do the routing like docker daemon do for me? – LarryLo Jan 15 '15 at 03:46
  • 5
    Possible duplicate of [How can I set a static IP address in a Docker container?](http://stackoverflow.com/questions/25529386/how-can-i-set-a-static-ip-address-in-a-docker-container) – Michael Hampton Jan 27 '16 at 08:10
  • It looks like this library has solved this problem. https://github.com/jpetazzo/pipework – LarryLo Apr 09 '15 at 09:16

8 Answers8

394

Easy with Docker version 1.10.1, build 9e83765.

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

docker network create --subnet=172.18.0.0/16 mynet123

then, 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/

Yennefer
  • 5,704
  • 7
  • 31
  • 44
cantSleepNow
  • 9,691
  • 5
  • 31
  • 42
  • 1
    Great answer - Just adding some additional info: https://blog.jessfraz.com/post/ips-for-all-the-things/ – Ole May 27 '16 at 19:13
  • @cantSleepNow for some reason I need just to use my own default created bridge br0 which is created in interfaces file during system boot (so it is NOT created using docker network create), could you suggest me how can I get the same effect of --ip parameter (get fixed IP address for a container) without creating my bridge using docker? – Mohammed Noureldin Oct 15 '16 at 10:14
  • @MohammedNoureldin I don't fully understand - also sounds like a new question, I think you should ask it as such. – cantSleepNow Oct 15 '16 at 10:33
  • @cantSleepNow I mean I need to fix the container's IP address though I am NOT using custom bridge (so --ip parameter cannot be used), do you suggest any way to get that? – Mohammed Noureldin Oct 15 '16 at 12:05
  • @MohammedNoureldin I'm not sure. As I said, post your question as question and not as a comment - maybe there is someone that knows the answer. – cantSleepNow Oct 15 '16 at 12:56
  • Great answer but if you won't add the "--name" at the time you are creating the container (in case you want to use the --hostname option)you will not be able to tell which is which as the hostname you can see only from inside the container. – DimiDak Dec 05 '18 at 22:29
  • "docker run --net mynet123 --ip 172.18.0.22 --name MyContainer --hostname MyContainer -it ubuntu bash" Worked great in my case. – DimiDak Dec 05 '18 at 22:32
  • One question, how do you modify an already running container without losing it's contents? I have several containers I would like to add these IP addresses to. – petrosmm Aug 09 '20 at 17:54
  • well, you should ask this as a separate question :) But in general, "contents" is not lost if it's within the mounted volume. – cantSleepNow Aug 12 '20 at 06:34
148

For docker-compose you can use following docker-compose.yml

version: '2'
services:
  nginx:
    image: nginx
    container_name: nginx-container
    networks:
      static-network:
        ipv4_address: 172.20.128.2
networks:
  static-network:
    ipam:
      config:
        - subnet: 172.20.0.0/16
          #docker-compose v3+ do not use ip_range
          ip_range: 172.28.5.0/24

from host you can test using:

docker-compose up -d
curl 172.20.128.2

Modern docker-compose does not change ip address that frequently.

To find ips of all containers in your docker-compose in a single line use:

for s in `docker-compose ps -q`; do echo ip of `docker inspect -f "{{.Name}}" $s` is `docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $s`; done

If you want to automate, you can use something like this example gist

zainengineer
  • 13,289
  • 6
  • 38
  • 28
24

Not a direct answer but it could help.

I run most of my dockerized services tied to own static ips using the next approach:

  1. I create ip aliases for all services on docker host
  2. Then I run each service redirecting ports from this ip into container so each service have own static ip which could be used by external users and other containers.

Sample:

docker run --name dns --restart=always -d -p 172.16.177.20:53:53/udp dns
docker run --name registry --restart=always -d -p 172.16.177.12:80:5000 registry
docker run --name cache --restart=always -d -p 172.16.177.13:80:3142 -v /data/cache:/var/cache/apt-cacher-ng cache
docker run --name mirror --restart=always -d -p 172.16.177.19:80:80 -v /data/mirror:/usr/share/nginx/html:ro mirror
...
ISanych
  • 21,590
  • 4
  • 32
  • 52
  • 1
    Thanks~ I know this. Just like https://github.com/brandon-rhodes/fopnp/tree/m/playground do. I will try it. – LarryLo Jan 15 '15 at 03:48
  • 2
    This is a very good solution, I would just attach this link for the new users to learn about aliasing http://www.cyberciti.biz/faq/linux-creating-or-adding-new-network-alias-to-a-network-card-nic/ – Mohammed Noureldin Oct 15 '16 at 15:20
  • Thank you for nice solution. – RavinderSingh13 May 26 '17 at 12:36
  • I am not clear how this answer can be useful in the context of the OP. The question is about assigning a static IP address to the container i.e., `172.16.177.20` to the `dns` container, but the command here would not work unless `dns` container is already assigned `172.16.177.20`. Where is the part that ensures that dns container actually gets the IP address `172.16.177.20`? What am I missing? – haridsv Nov 17 '21 at 10:17
5

I stumbled upon this problem during attempt to dockerise Avahi which needs to be aware of its public IP to function properly. Assigning static IP to the container is tricky due to lack of support for static IP assignment in Docker.

This article describes technique how to assign static IP to the container on Debian:

  1. Docker service should be started with DOCKER_OPTS="--bridge=br0 --ip-masq=false --iptables=false". I assume that br0 bridge is already configured.

  2. Container should be started with --cap-add=NET_ADMIN --net=bridge

  3. Inside container pre-up ip addr flush dev eth0 in /etc/network/interfaces can be used to dismiss IP address assigned by Docker as in following example:


auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    pre-up ip addr flush dev eth0
    address 192.168.0.249
    netmask 255.255.255.0
    gateway 192.168.0.1
  1. Container's entry script should begin with /etc/init.d/networking start. Also entry script needs to edit or populate /etc/hosts file in order to remove references to Docker-assigned IP.
Onlyjob
  • 5,692
  • 2
  • 35
  • 35
4

This works for me.

Create a network with docker network create --subnet=172.17.0.0/16 selnet

Run docker image docker run --net selnet --ip 172.18.0.2 hub

At first, I got

docker: Error response from daemon: Invalid address 172.17.0.2: It does not belong to any of this network's subnets.
ERRO[0000] error waiting for container: context canceled

Solution: Increased the 2nd quadruple of the IP [.18. instead of .17.]

Edric
  • 24,639
  • 13
  • 81
  • 91
Nils Zenker
  • 659
  • 7
  • 11
  • 7
    There's a 2 years older similar/identical answer elsewhere on this page: https://stackoverflow.com/a/35359185/694469 – KajMagnus Jan 08 '19 at 15:08
3

You can set the IP while running it.

docker run --cap-add=NET_ADMIN -dit imagename /bin/sh -c "/sbin/ip addr add 172.17.0.12 dev eth0; bash"

See my example at https://github.com/RvdGijp/mariadb-10.1-galera

HowRude
  • 47
  • 1
  • unfortunately this adds one more IP address, if an IP address was assigned in the process before, this results in having two IP addresses – davey Apr 04 '18 at 04:46
2

You can access other containers' service by their name(ping apachewill get the ip or curl http://apache would access the http service) And this can be a alternative of a static ip.

Guisong He
  • 1,886
  • 1
  • 15
  • 27
  • 3
    In the docker version of 1.8 this works directly. In the newer version, you must fistly link these containers. – Guisong He Mar 03 '16 at 09:59
  • This is the best solution, unfortunately summer services require an IP and not a name (along others Home Assistant when configuring trusted proxies) – WoJ Jul 20 '22 at 11:59
0

If you want your container to have it's own virtual ethernet socket (with it's own MAC address), iptables, then use the Macvlan driver. This may be necessary to route traffic out to your/ISPs router.

https://docs.docker.com/engine/userguide/networking/get-started-macvlan

FlappySocks
  • 3,772
  • 3
  • 32
  • 33