Как назначить сопоставление портов для существующего контейнера Docker?


437

Я не уверен, что я что-то здесь неправильно понял, но кажется, что установить сопоставления портов можно только путем создания нового контейнера из образа. Есть ли способ назначить сопоставление портов для существующего контейнера Docker?


3
Использование iptables может работать так: ответ на порт в контейнере Live Docker
Choldrim

2
Я подозреваю, что это по замыслу. Докер пытается заставить вас быть «повторяемыми», а контейнер - это «система записи». Все, что вы делаете как шаг, не влияющий на контейнер, будет легко потерянным ручным шагом. Сказано иначе: вы хотите, чтобы ваш контейнер представлял всю конфигурацию, необходимую для работы. Так что если вы хотите открыть новый порт, то вам нужно создать новый контейнер.
Ланс Кинд

2
Старый вопрос, и я не отвечаю на него, но я хотел бы сказать, что, возможно, вы и люди, задающие этот вопрос и ответы, возможно, совершенно неправильно поняли концепцию докера. Докер предназначен для приложений без сохранения состояния, которые могут увеличиваться или уменьшаться во много раз. Вы никогда не должны сохранять что-то внутри контейнера для производственной среды, которую невозможно воссоздать, если вам нужно сохранить, сопоставьте каталоги. Docker - это не что-то вроде «light vm», может быть, вы ищете linuxcontainers.org, lxd основан на концепции докера, но имеет в виду «light vm».
Эдгар Карвалью

на всякий случай это может помочь, можно использовать инструмент «Kitematic», чтобы добавить сопоставление портов для уже запущенных контейнеров. Это должно подразумевать, что должна быть команда docker, чтобы сделать то же самое, но с небольшим
поиском в

Ответы:


298

Вы можете изменить отображение портов, отредактировав hostconfig.jsonфайл по адресу /var/lib/docker/containers/[hash_of_the_container]/hostconfig.json

Вы можете определить [hash_of_the_container] с помощью docker inspect <container_name>команды, а значение поля «Id» - это хеш.

1) stop the container 
2) stop docker service (per Tacsiazuma's comment)
3) change the file
4) restart your docker engine (to flush/clear config caches)
5) start the container

Таким образом, вам не нужно создавать изображение с этим подходом. Вы также можете изменить флаг перезагрузки здесь.

PS Вы можете посетить https://docs.docker.com/engine/admin/, чтобы узнать, как правильно перезапустить механизм докера в соответствии с вашим хост-компьютером. Я использовал, sudo systemctl restart dockerчтобы перезапустить мой механизм докера, который работает на Ubuntu 16.04


17
Когда докер останавливается, кажется, что он перезаписывает ваши изменения, поэтому 2. остановите докер, 3. измените файл, 4. запустите механизм докера
Tacsiazuma

5
Я попробовал выше, и это работает. Для получения дополнительной информации см .: mybrainimage.wordpress.com/2017/02/05/…
rohitmohta

11
Важно остановить контейнер, остановить двигатель докера и изменить оба этих параметра hostconfig.jsonи config.v2.jsonзаставить это работать. Используйте ссылку, предоставленную @rohitmohta, чтобы увидеть детали.
Калпак Гадре

5
работал для меня, только одна вещь, если вы используете приложение docker на Mac, следуйте инструкциям здесь, чтобы перейти в папку / var / lib / docker / Containers: stackoverflow.com/a/41226917/2048266 , в основном запустить screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/ttyПосле того, как вы запустите tty, вы можете перейти к / var / lib / docker
nom

14
для Windows, пожалуйста, можете ли вы поделиться мне расположение папки conatiners.?
Виджей

463

Я также заинтересован в этой проблеме.

Как упоминалось в @Thasmo , переадресацию портов можно задавать ТОЛЬКО с помощью команды docker rundocker create).
Другие команды, docker startне имеют -pопции и docker portотображают только текущие пересылки.

Чтобы добавить переадресацию портов, я всегда следую за этими шагами,

  1. остановить запуск контейнера

    docker stop test01
    
  2. совершить контейнер

    docker commit test01 test02
    

    ПРИМЕЧАНИЕ: выше, test02это новое изображение, которое я создаю из test01контейнера.

  3. повторно запустить из порученного изображения

    docker run -p 8080:8080 -td test02
    

Где первый 8080 является локальным портом, а второй 8080 является портом контейнера.


15
Что если я хочу сохранить имя test01?
user69715

12
Кто-нибудь знает, есть ли открытая проблема с Docker, чтобы разрешить спецификацию порта (--publish) с docker start?
Элайджа Линн

8
И что происходит с объемами в этом сценарии?
Андрей Савиных

78
Это ужасное решение, я понятия не имею, как ему удалось заработать 250 голосов. Может быть, те, кто проголосовал, не знали, какой беспорядок вызывает это решение. Да, это ужасно, и это равносильно запуску нового контейнера, работающего на другом порту.
Arrrr

25
@Arrrr Может быть, вы хотите оставить лучший ответ? Я уверен, что мы все были бы признательны, если бы вы сказали нам гораздо лучший способ сделать это.
Crockeea

40

Если под «существующим» вы подразумеваете «работающий», то (в настоящее время) невозможно добавить сопоставление портов.

Однако вы можете динамически добавить новый сетевой интерфейс, например, с помощью Pipework , если вам нужно представить сервис в работающем контейнере без его остановки / перезапуска.


4
Это должен быть главный ответ. Сжато, и это отвечает на вопрос OP, который никто из остальных не делает! Иногда отрицательный результат есть результат!
Небольшая

19

Не уверен, что вы можете применить сопоставление портов для работающего контейнера. Вы можете применить переадресацию портов при запуске контейнера, который отличается от создания нового контейнера.

$ docker run -p <public_port>:<private_port> -d <image>  

начнется запуск контейнера. Этот урок объясняет перенаправление портов.


2
Да, так что, кажется, можно только установить параметры, такие как сопоставление портов при создании контейнера.
thasmo

20
К вашему сведению, этот ответ не совсем правильный. docker runсоздает и запускает новый контейнер. Это эквивалентно выполнению, docker createза которым следует docker start.
Тревор Салливан

19

Редактирование hostconfig.json сейчас не работает. Это заканчивается только тем, что этот порт открыт, но не опубликован для хоста. Создание и воссоздание контейнеров - не лучший подход для меня. Никто не упомянул docker network?

Лучшим решением было бы использование обратного прокси в той же сети

  1. Создайте новую сеть, если ваш предыдущий контейнер не указан ни в одной из них.

    docker network create my_network

  2. Присоедините существующий контейнер к созданной сети

    docker network connect my_network my_existing_container

  3. Запустите службу обратного прокси (например, nginx), публикуя нужные порты и подключаясь к той же сети.

    docker run -d --name nginx --network my_network -p 9000:9000 nginx

    При желании удалите default.conf в nginx

    docker exec nginx rm /etc/nginx/conf.d/default.conf

  4. Создайте новый конфиг nginx

    server
    {
        listen 9000;
    
        location / {
            proxy_pass http://my_existing_container:9000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
    }
    

    Скопируйте конфигурацию в контейнер nginx.

    docker cp ./my_conf.conf nginx:/etc/nginx/conf.d/my_conf.conf

  5. Перезапустите nginx

    docker restart nginx

Преимущества : чтобы опубликовать новые порты, вы можете безопасно остановить / обновить / воссоздать контейнер nginx по своему усмотрению, не касаясь бизнес-контейнера. Если вам нужно нулевое время простоя для nginx, можно добавить больше обращенных прокси-сервисов, присоединяющихся к той же сети. Кроме того, контейнер может присоединиться к нескольким сетям.

Редактировать:

Для обратного прокси не-http сервисы, файл конфигурации немного отличается. Вот простой пример:

upstream my_service {
    server my_existing_container:9000;
}

server {
    listen 9000;
    proxy_pass my_service;
}

1
Это удивительно и практично, но для корпоративных систем этот подход кажется запутывающим. Гораздо лучше позволить единой системе контролировать рабочий процесс.
Афшин

1
@Afshin Хорошо для корпоративных систем или проектов, я думаю, что это решение лучше, чем воссоздание (вызывает простоя) или взлом файла hostconfig.json (по крайней мере, официально не представлен). Дополнительный контейнер просто отображает внутренний порт вашего бизнес-контейнера, а не вносит в него какие-либо изменения.
Шон С.

1
Потрясающий подход. Мне нужно было настроить nginx по-другому, чтобы мой контейнер работал за прокси-сервером, но кажется, что это правильный путь. Работает для сине-зеленого развертывания тоже.
Брукс Дюбуа

18

В примере Fujimoto Youichi test01это контейнер, а test02изображение.

Перед этим docker runвы можете удалить исходный контейнер, а затем снова присвоить ему то же имя:

$ docker stop container01
$ docker commit container01 image01
$ docker rm container01
$ docker run -d -P --name container01 image01

(Использование -Pдля выставления портов для случайных портов, а не для назначения вручную).


12
Пожалуйста, будьте осторожны. вы потеряете все свои данные, в зависимости от приложения внутри.
Барри

14

Если вы запустите docker run <NAME>его, появится новый образ, который, скорее всего, не тот, который вы хотите.

Если вы хотите изменить текущее изображение, сделайте следующее:

docker ps -a

Возьмите идентификатор вашего целевого контейнера и перейдите к:

cd /var/lib/docker/containers/<conainerID><and then some:)>

Остановить контейнер:

docker stop <NAME>

Изменить файлы

vi config.v2.json

"Config": {
    ....
    "ExposedPorts": {
        "80/tcp": {},
        "8888/tcp": {}
    },
    ....
},
"NetworkSettings": {
....
"Ports": {
     "80/tcp": [
         {
             "HostIp": "",
             "HostPort": "80"
         }
     ],

И изменить файл

vi hostconfig.json

"PortBindings": {
     "80/tcp": [
         {
             "HostIp": "",
             "HostPort": "80"
         }
     ],
     "8888/tcp": [
         {
             "HostIp": "",
             "HostPort": "8888"
         } 
     ]
 }

Перезагрузите докер, и он должен работать.


2
Это не сработало для меня в Docker версии 17.09.0-ce. После того, как я запустил файлы конфигурации контейнера, они были перезаписаны обратно к старым значениям.
thegeko

3
перезапустите службу докера в хост-системе @thegeko
yurenchen

1
это работает! ТКС! 1. остановить контейнер, 2. изменить файлы, 3. перезагрузить докер, 4. запустить обратно контейнер
datdinhquoc

12

И наоборот, если вас не устраивает конфигурация глубины Docker, IPtables будет вашим другом.

iptables -t nat -A DOCKER -p tcp --dport ${YOURPORT} -j DNAT --to-destination ${CONTAINERIP}:${YOURPORT}

iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source ${CONTAINERIP} --destination ${CONTAINERIP} --dport ${YOURPORT}

iptables -A DOCKER -j ACCEPT -p tcp --destination ${CONTAINERIP} --dport ${YOURPORT}

Это просто трюк, а не рекомендуемый способ, который работает с моим сценарием, потому что я не смог остановить контейнер, надеюсь, он вам тоже поможет.


это отличный ответ! Спасибо! Если я хочу , чтобы отобразить DOCKER_PORTв MACHINE_PORT, какие части должны быть изменены?
Ciprian Tomoiagă

Примечание докер не будет знать об этом ручном дополнении. Записи SO не удаляются при последующем перезапуске службы с помощью докера, правильно отображающего порты. Поэтому, когда что-то меняется, обязательно внимательно проверьте iptables. Особенно ищите дубликаты записей!
Энтони

8

мы используем удобные инструменты, такие как ssh, чтобы легко это сделать.

Я использовал образ хоста Ubuntu и основанный на Ubuntu образ докера.

  1. Внутри докера установлен openssh-клиент.
  2. На внешнем докере (хосте) установлен сервер openssh-server.

когда новый порт необходимо отобразить,

внутри докера выполните следующую команду

ssh -R8888:localhost:8888 <username>@172.17.0.1

172.17.0.1 был ip интерфейса докера (вы можете получить это, запустив ifconfig docker0 | grep "inet addr" | cut -f2 -d":" | cut -f1 -d" "на хосте).

здесь у меня был локальный порт 8888, сопоставленный с хостами 8888. Вы можете изменить порт при необходимости.

если вам нужен еще один порт, вы можете убить ssh и добавить в него еще одну строку -R с новым портом.

Я проверил это с Netcat.


2
  1. Остановите двигатель докера и этот контейнер.
  2. Перейти в /var/lib/docker/containers/${container_id}каталог и редактироватьhostconfig.json
  3. Отредактируйте, PortBindings.HostPortчто вы хотите изменить.
  4. Запустите двигатель докера и контейнер.

-1

Для пользователей Windows и Mac есть еще один довольно простой и удобный способ изменить порт отображения:

  1. скачать Kitematic

  2. перейдите на страницу настроек контейнера, на вкладке портов вы можете напрямую изменить опубликованный порт.

  3. запустить контейнер снова


2
Я попробовал этот подход. Kinematic действительно применил сопоставления портов. Однако чтобы применить их, он заново создал мой контейнер из исходного изображения. Поэтому, если вы боитесь потерять изменения, сделанные в самом контейнере, не используйте этот метод.
VeganHunter

1
Я предпочел это, я понял, что он не отвечает на вопрос, и создает новый контейнер. Но, по крайней мере, это работает, и этот ТАКИЙ результат обнаружился во время моего поиска. +1
2b77bee6-5445-4c77-b1eb-4df3e5

-7

Краткий ответ: Вы не можете назначить сопоставление портов существующему контейнеру Docker.

Вам нужен новый контейнер ... разберитесь с ним.


4
Нет необходимости в отношении. Также в этом ответе совершенно отсутствуют детали.
lovefaithswing

1
Нет необходимости в деталях. Тон имеет решающее значение, чтобы передать этот экономящий время ответ и эфемерную природу контейнеров.
Стивен

-11

Если вы просто хотите изменить порт работающего контейнера, вы делаете:

  1. остановить существующий контейнер

    sudo docker stop NAME

  2. Теперь перезапустите с новым сопоставлением портов

    sudo docker run -d -p 81:80 ИМЯ

в то время как:

"-d" для фона / deamon докер

«-p» включить сопоставление портов

«81» внешний (открытый) порт, который вы используете для доступа через браузер

"80" порт прослушивания внутреннего док-контейнера


4
Это просто неправильно. В docker runкоманде, NAMEэто имя изображения , чтобы запустить контейнер из, тогда как в относится к имени контейнера до остановки. docker stopNAME
Джонатан

1
«Docker run» создаст новый контейнер. Он не может использовать то же имя контейнера, что и тот, который был остановлен, потому что вы можете иметь только один контейнер с этим именем. Поэтому вам нужно будет сделать: «docker stop NAME», docker container rm NAME, а затем «docker run -d -p 81:80 NAME», как вы его написали.
Lance Kind
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.