Docker推送拉取后如何保留OwnCloud的数据与公共链接?
问题背景
我有一个Web服务器程序需要从OwnCloud服务器获取PDF文件,正在通过Docker Compose与Docker Hub制作安装代码,使用Ubuntu 20.04LTS和Docker Compose v2.1.0。操作流程如下:
- 在OwnCloud Docker容器的
/var/www/owncloud/data目录下存储PDF文件并创建公共链接; - 通过
docker commit命令基于容器创建OwnCloud、MariaDB新镜像并推送至Docker Hub; - 在全新Ubuntu服务器上拉取镜像并执行
docker-compose up。
但操作后,新服务器上的OwnCloud无PDF文件,所有配置(账号、MariaDB数据库配置)被初始化,进入启动配置页面。最初尝试过OwnCloud官方镜像,发现其将数据存储在外部Docker卷中,我认为这是数据丢失的原因,因此改为手动安装。
相关配置文件(关联部分):
docker-compose.yml
owncloud: #build: ./dockerfiles/owncloud/ image: "dockerhubid/docker-owncloud" container_name: chatbot_owncloud restart: always networks: - chatbot_network depends_on: - mariadb volumes: - 'owncloud_php:/var/www/owncloud' command: php-fpm7.4 -F -R mariadb: # build: ./dockerfiles/mariadb/ image: dockerhubid/docker-mariadb container_name: mariadb restart: always expose: - '3306' networks: - chatbot_network environment: - MYSQL_ROOT_PASSWORD=password - MYSQL_USER=owncloud - MYSQL_PASSWORD=password - MYSQL_DATABASE=owncloud command: ["--max-allowed-packet=128M", "--innodb-log-file-size=64M"] nginx: #build: ./dockerfiles/nginx/ image: "dockerhubid/docker-nginx" container_name: chatbot_nginx restart: always depends_on: - owncloud volumes: - ./dockerfiles/certbot/conf:/etc/letsencrypt - ./dockerfiles/certbot/www:/var/www/certbot volumes_from: - 'owncloud:ro' networks: - chatbot_network ports: - '80:80' - '3000:3000' - '8883:8883' - '8884:8884' command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'" certbot: image: certbot/certbot container_name: chatbot_certbot networks: - chatbot_network volumes: - ./dockerfiles/certbot/conf:/etc/letsencrypt - ./dockerfiles/certbot/www:/var/www/certbot entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
owncloud Dockerfile
FROM ubuntu:20.04 EXPOSE 9000 ARG DEBIAN_FRONTEND=noninteractive # dependencies RUN apt update && apt upgrade -y RUN apt install -y php-bz2 php-curl php-gd php-imagick php-intl php-mbstring php-xml php-zip php-mysql php-fpm wget zip vim # owncloud RUN wget https://download.owncloud.org/community/owncloud-10.5.0.zip RUN unzip owncloud-10.5.0.zip -d /var/www/ RUN rm /owncloud-10.5.0.zip WORKDIR /var/www/owncloud RUN chown www-data:www-data -R /usr/bin/php /var/www/owncloud/ RUN chmod -R 755 /var/www/owncloud/ # php-fpm setup RUN sed -i 's+/run/php/php7.4-fpm.sock+9000+g' /etc/php/7.4/fpm/pool.d/www.conf ADD init.sh /docker-entrypoint-initdb.d/ RUN chmod 755 /docker-entrypoint-initdb.d/init.sh
mariadb Dockerfile
from mariadb:10.5 EXPOSE 3306 ARG DEBIAN_FRONTEND=noninteractive USER root ADD init.sql /docker-entrypoint-initdb.d/ RUN chmod 755 /docker-entrypoint-initdb.d/init.sql
原因分析
Docker commit不包含卷数据:你的
docker-compose.yml中为OwnCloud挂载了owncloud_php:/var/www/owncloud卷,容器内该路径的实际数据存储在卷中,而非容器的可写层。docker commit只会打包容器的可写层内容,卷数据不会被包含到镜像里。新服务器启动时会创建新的空卷,覆盖镜像中的内容,导致之前的PDF文件和配置丢失。MariaDB数据未被捕获:官方MariaDB镜像默认将数据库数据存储在
/var/lib/mysql卷中,docker commit同样不会包含该卷的数据。新服务器启动MariaDB容器时,会初始化全新的数据库,导致OwnCloud无法读取原有配置,进入初始化页面。卷挂载覆盖了镜像内容:你手动构建的OwnCloud镜像将程序安装在
/var/www/owncloud,但启动时用卷挂载了整个目录,镜像中的程序和配置会被空卷覆盖,即使你commit了容器,卷的内容也没被包含进去,新环境启动后自然没有原有数据。
解决方法
1. 放弃docker commit,改用标准化镜像构建+数据卷迁移
docker commit仅适合临时调试,不适合生产环境的镜像分发,因为它会打包容器的临时状态,无法保证构建的可重复性,且不包含卷数据。正确的做法是用Dockerfile构建纯净镜像,单独迁移数据卷内容。
2. 分离OwnCloud程序与数据
修改docker-compose.yml的OwnCloud服务,只挂载数据和配置目录,避免覆盖整个程序目录:
owncloud: image: "dockerhubid/docker-owncloud" container_name: chatbot_owncloud restart: always networks: - chatbot_network depends_on: - mariadb volumes: # 仅挂载数据和配置目录,保留镜像中的核心程序 - owncloud_data:/var/www/owncloud/data - owncloud_config:/var/www/owncloud/config command: php-fpm7.4 -F -R
3. 迁移原有数据与配置
在原服务器上执行以下命令备份数据:
- 备份OwnCloud数据卷:
# 备份data目录 docker run --rm -v owncloud_data:/data -v $(pwd):/backup ubuntu tar cvzf /backup/owncloud_data.tar.gz /data # 备份config目录 docker run --rm -v owncloud_config:/config -v $(pwd):/backup ubuntu tar cvzf /backup/owncloud_config.tar.gz /config - 备份MariaDB数据库:
docker exec mariadb mysqldump -u root -ppassword owncloud > owncloud_db.sql
将备份文件传到新服务器后,执行以下恢复操作:
- 恢复OwnCloud数据卷:
docker run --rm -v owncloud_data:/data -v $(pwd):/backup ubuntu bash -c "tar xvzf /backup/owncloud_data.tar.gz --strip-components=1 -C /data" docker run --rm -v owncloud_config:/config -v $(pwd):/backup ubuntu bash -c "tar xvzf /backup/owncloud_config.tar.gz --strip-components=1 -C /config" - 恢复MariaDB数据库:
cat owncloud_db.sql | docker exec -i mariadb mysql -u root -ppassword owncloud
4. 优化MariaDB配置,挂载数据卷
修改docker-compose.yml的MariaDB服务,挂载数据库数据卷,避免数据丢失:
mariadb: image: dockerhubid/docker-mariadb container_name: mariadb restart: always expose: - '3306' networks: - chatbot_network environment: - MYSQL_ROOT_PASSWORD=password - MYSQL_USER=owncloud - MYSQL_PASSWORD=password - MYSQL_DATABASE=owncloud volumes: # 挂载MariaDB数据卷 - mariadb_data:/var/lib/mysql command: ["--max-allowed-packet=128M", "--innodb-log-file-size=64M"]
5. 预置初始化配置(可选)
如果需要在镜像中预置基础配置,可以修改init.sh,当config目录为空时自动复制默认配置并设置数据库连接:
#!/bin/bash if [ ! -f /var/www/owncloud/config/config.php ]; then cp /var/www/owncloud/config/config.sample.php /var/www/owncloud/config/config.php # 替换数据库连接信息 sed -i 's/localhost/mariadb/g' /var/www/owncloud/config/config.php sed -i 's/owncloud/'"$MYSQL_DATABASE"'/g' /var/www/owncloud/config/config.php sed -i 's/root/'"$MYSQL_USER"'/g' /var/www/owncloud/config/config.php sed -i 's/""'"'/'"$MYSQL_PASSWORD"'/g' /var/www/owncloud/config/config.php fi exec "$@"
内容的提问来源于stack exchange,提问作者sanghyeup lee

