Docker - изменение данных в volumes
Docker разработчики рекомендуют использовать volumes для хранения данных контейнера, и это хорошо работает если приложение контейнера само меняет данные. Но ситуация когда нужно обновить код скрипта в контейнере - работает непонятно. Даже если я удаляю хранилище контейнера и создаю снова (через docker-compose) - файл копируется в хранилище не измененный. Версионность volumes как я понял тоже не поддерживается. Вариант с физическим копированием нужных файлов в /var/lib/docker/volumes/ - не совсем верный. Остается вариант только монтировать нужный каталог внутрь контейнера (как это рекомендуется для конфигурационных файлов)? Или я что то упускаю? Заранее спасибо за ответ!
Дополнение:
docker-compose.yml
version: '3.8'
services:
server:
build:
context: .
dockerfile: Dockerfile
image: nodejs
restart: unless-stopped
environment:
- PORT=3000
- MYSQL_HOSTNAME=db
- MYSQL_USERNAME=user
- MYSQL_PASSWORD=passwd
- MYSQL_DB=db
ports:
- "3000:3000"
volumes:
- server:/home/node/server
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
server:
Docker файл:
FROM node:14
WORKDIR /home/node/server
COPY ./server/package*.json ./
RUN npm install
COPY ./server ./
CMD ["node", "server.js"]
в текущей директории есть директория server и в ней server.js файл
Запускаю контейнер docker-compose up, смотрю что все запустилось и работает, сервер Node отдает нужные данные, останавливаю контейнер и удаляю через docker-compose down
После - копирую в директорию ./server новый файл server.js и тут пробовал такие варианты:
- docker-compose build --force-rm --no-cache
docker-compose up - в контейнере остается старый файл - останавливаю контейнер, удаляю контейнер и удаляю хранилище через docker volume rm server, стартую docker-compose up - вижу что операции копирования выполняются - но копируется все равно не измененный файл, хотя его уже нет в папке ./server
- Делаю как в варианте 2 но создаю пустой контейнер перед запуском docker volume create server, и запускаю docker-compose up, тут в двух случаях из 15 - файл обновляется, объяснения этому не нашел.
Ответы (1 шт):
Вы используете инструмент не по назначению, вот у вас и возникают проблемы. volume предназначены для хранения данных между запусками контейнера. Скрипт - это не данные.
Есть два канонических сценария как код попадает в контейнер:
- во время CI - сборка образа и код добавляется в Dockerfile через COPY
- если контейнер используется для разработки, тогда через bind mount-ы
С первым все ясно - вы хотите другого. Вот демо второго способа.
$ cat docker-compose.yml
version: '3.8'
services:
server:
image: alpine:latest
volumes:
- ./server:/server
$ ls server
1
$ (sleep 5 && touch server/2) &
[1] 55190
$ docker-compose run server /bin/sh -c "while true; do ls /server; sleep 1; done"
Creating 1281969-docker-volumes_server_run ... done
1
1
1 2
1 2
^C[1]+ Done ( sleep 5 && touch server/2 )
Можно конечно поместить код и в volume. Копировать данные можно с помощью docker cp, когда контейнер запущен (этот и или любой другой, надо только присоединить volume).
Допустим есть compose файл:
version: '3.8'
services:
server:
image: alpine:latest
volumes:
- server:/server
volumes:
server:
Запускаем какой-нибудь контейнер и используем:
docker run -ti -v server:/whatever --rm --name temp alpine:latest /bin/sh
И теперь можно копировать файлы в volume:
docker cp server/server.js temp:/whatever/server.js