Docker`COPY`文件到容器中不是持久性的

时间:2019-04-21 11:34:34

标签: docker kubernetes copy

我已经为该应用创建了一个docker映像,其中我正在将文件夹复制到该映像中,如下所示:

COPY extra-addons/ /mnt/extra-addons/pos_item_price/

但是当我使用Kubernetes使用该图像并转到/ mnt / extra-addons文件夹

$ kubectl --insecure-skip-tls-verify --namespace my-app exec -it my-app-55d464dd78-7h7x7 -- /bin/bash
root@my-app-55d464dd78-7h7x7:/# cd /mnt/extra-addons/
root@my-app-55d464dd78-7h7x7:/mnt/extra-addons# ls
root@my-app-55d464dd78-7h7x7:/mnt/extra-addons#

我什么都没看到

但是我确实在构建图像时看到正在复制数据

Step 19/26 : COPY extra-addons/ /mnt/extra-addons/pos_item_price/
---> 47fda7baba98
Step 20/26 : RUN ls -la /mnt/extra-addons/*
---> Running in ab93cf423db5
total 12
drwxr-xr-x. 3 odoo root 4096 Apr 21 11:13 .
drwxr-xr-x. 3 odoo root 4096 Apr 21 11:13 ..
drwxrwxrwx. 7 root root 4096 Apr 21 11:13 pos_item_price
Removing intermediate container ab93cf423db5
---> 645bc64741e0
Step 21/26 : RUN ls -la /mnt/extra-addons/pos_item_price/*
---> Running in f6ad09d6d83c
total 44
drwxrwxrwx. 7 root root 4096 Apr 21 11:13 .
drwxr-xr-x. 3 odoo root 4096 Apr 21 11:13 ..
-rw-rw-rw-. 1 root root 77 Apr 21 11:10 .git
-rw-rw-rw-. 1 root root 579 Apr 21 11:10 .gitignore
-rw-rw-rw-. 1 root root 45 Apr 21 11:10 __init__.py
-rw-rw-rw-. 1 root root 571 Apr 21 11:10 __manifest__.py
drwxrwxrwx. 2 root root 4096 Apr 21 11:13 data
drwxrwxrwx. 2 root root 4096 Apr 21 11:13 models
drwxrwxrwx. 2 root root 4096 Apr 21 11:13 security
drwxrwxrwx. 3 root root 4096 Apr 21 11:13 static
drwxrwxrwx. 2 root root 4096 Apr 21 11:13 views
Removing intermediate container f6ad09d6d83c
---> dc35af25b2a8

我想知道为什么当我将其复制到映像中时它不是持久性的,我希望数据会出现在kubernetes容器中吗?

完整的Dockerfile

FROM debian:stretch

# Generate locale C.UTF-8 for postgres and general locale data
ENV LANG C.UTF-8

# Install some deps, lessc and less-plugin-clean-css, and wkhtmltopdf
RUN set -x; \
        apt-get update \
        && apt-get install -y --no-install-recommends \
            ca-certificates \
            curl \
            dirmngr \
            fonts-noto-cjk \
            gnupg \
            libssl1.0-dev \
            node-less \
            python3-pip \
            python3-pyldap \
            python3-qrcode \
            python3-renderpm \
            python3-setuptools \
            python3-vobject \
            python3-watchdog \
            xz-utils \
        && curl -o wkhtmltox.deb -sSL https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.stretch_amd64.deb \
        && echo '7e35a63f9db14f93ec7feeb0fce76b30c08f2057 wkhtmltox.deb' | sha1sum -c - \
        && dpkg --force-depends -i wkhtmltox.deb\
        && apt-get -y install -f --no-install-recommends \
        && rm -rf /var/lib/apt/lists/* wkhtmltox.deb

# install latest postgresql-client
RUN set -x; \
        echo 'deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main' > etc/apt/sources.list.d/pgdg.list \
        && export GNUPGHOME="$(mktemp -d)" \
        && repokey='B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8' \
        && gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "${repokey}" \
        && gpg --armor --export "${repokey}" | apt-key add - \
        && gpgconf --kill all \
        && rm -rf "$GNUPGHOME" \
        && apt-get update  \
        && apt-get install -y postgresql-client \
        && rm -rf /var/lib/apt/lists/*

# Install rtlcss (on Debian stretch)
RUN set -x;\
    echo "deb http://deb.nodesource.com/node_8.x stretch main" > /etc/apt/sources.list.d/nodesource.list \
    && export GNUPGHOME="$(mktemp -d)" \
    && repokey='9FD3B784BC1C6FC31A8A0A1C1655A0AB68576280' \
    && gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "${repokey}" \
    && gpg --armor --export "${repokey}" | apt-key add - \
    && gpgconf --kill all \
    && rm -rf "$GNUPGHOME" \
    && apt-get update \
    && apt-get install -y nodejs \
    && npm install -g rtlcss \
    && rm -rf /var/lib/apt/lists/*

# Install Odoo
ENV ODOO_VERSION 12.0
ARG ODOO_RELEASE=20190128
ARG ODOO_SHA=9e34aaed2eb1e7697aaf36767247dbf335e9fe7a
RUN set -x; \
        curl -o odoo.deb -sSL http://nightly.odoo.com/${ODOO_VERSION}/nightly/deb/odoo_${ODOO_VERSION}.${ODOO_RELEASE}_all.deb \
        && echo "${ODOO_SHA} odoo.deb" | sha1sum -c - \
        && dpkg --force-depends -i odoo.deb \
        && apt-get update \
        && apt-get -y install -f --no-install-recommends \
        && rm -rf /var/lib/apt/lists/* odoo.deb

# Copy entrypoint script and Odoo configuration file
RUN pip3 install num2words xlwt
COPY ./entrypoint.sh /
COPY ./odoo.conf /etc/odoo/
RUN chown odoo /etc/odoo/odoo.conf

# Mount /var/lib/odoo to allow restoring filestore and /mnt/extra-addons for users addons
RUN mkdir -p /mnt/extra-addons/pos_item_price \
        && chown -R odoo /mnt/extra-addons
VOLUME ["/var/lib/odoo", "/mnt/extra-addons"]

RUN ls -la /mnt/extra-addons/*
RUN echo "-------- Before LS END -----"
COPY extra-addons/ /mnt/extra-addons/pos_item_price/
RUN ls -la /mnt/extra-addons/*
RUN ls -la /mnt/extra-addons/pos_item_price/*

# Expose Odoo services
EXPOSE 8069 8071

# Set the default config file
ENV ODOO_RC /etc/odoo/odoo.conf

# Set default user when running the container
USER odoo

ENTRYPOINT ["/entrypoint.sh"]
CMD ["odoo"]

1 个答案:

答案 0 :(得分:3)

我相信您面临的问题与您的卷有关,但与Dockerfile中定义的卷无关(尽管我个人不喜欢在Dockerfile中定义的任何卷,因为它们会引起问题)。

要解释由Dockerfile中的VOLUME引起的问题,您可以看到以下示例来测试COPY,ADD和RUN:

$ cat df.vol
FROM busybox:latest

VOLUME ["/data"]
CMD find /data

COPY sample-data/file.txt /data/file.txt
COPY sample-data/dir /data/dir
ADD sample-data/tar-file.tgz /data/tar-dir
RUN echo "hello world" >/data/run.txt \
 && find /data \
 && sleep 5m

以下是用于COPY和ADD命令的示例数据目录:

$ ls -al sample-data/
total 32 
drwxr-xr-x  3 bmitch bmitch  4096 Jan 22  2017 .
drwxr-xr-x 34 bmitch bmitch 12288 Apr 17 15:16 ..
drwxr-xr-x  2 bmitch bmitch  4096 Jan 22  2017 dir
-rw-r--r--  1 bmitch bmitch    14 Jan 22  2017 file2.txt
-rw-r--r--  1 bmitch bmitch    12 Jan 22  2017 file.txt
-rw-r--r--  1 bmitch bmitch   214 Jan 22  2017 tar-file.tgz

让我们运行一个构建(因为我们想调试它,所以没有BUILDKIT):

$ DOCKER_BUILDKIT=0 docker build -f df.vol -t test-vol .
Sending build context to Docker daemon  23.04kB
Step 1/7 : FROM busybox:latest
 ---> 59788edf1f3e
Step 2/7 : VOLUME ["/data"]
 ---> Using cache
 ---> 14b4f1130806                      
Step 3/7 : CMD find /data     
 ---> Running in 75673363d1e3             
Removing intermediate container 75673363d1e3
 ---> 262714d065fc
Step 4/7 : COPY sample-data/file.txt /data/file.txt
 ---> d781519c584e
Step 5/7 : COPY sample-data/dir /data/dir
 ---> 34b5b4a83b1e
Step 6/7 : ADD sample-data/tar-file.tgz /data/tar-dir
 ---> 3fc45f2e62a4                                                
Step 7/7 : RUN echo "hello world" >/data/run.txt  && find /data  && sleep 5m
 ---> Running in d75794387274
/data
/data/dir
/data/dir/file1.txt
/data/dir/file2.txt
/data/run.txt
/data/tar-dir
/data/tar-dir/dir
/data/tar-dir/dir/file1.txt
/data/tar-dir/dir/file2.txt
/data/tar-dir/file.txt
/data/file.txt
Removing intermediate container d75794387274
 ---> 5af322be539a
Successfully built 5af322be539a
Successfully tagged test-vol:latest

请注意上面的run.txt文件。我们还可以从COPY和ADD命令中看到文件。但是,如果我们运行另一个RUN命令,或者任何时候使用生成的图像,我们都会看到:

$ docker run -it --rm test-vol:latest
/data
/data/dir
/data/dir/file1.txt
/data/dir/file2.txt
/data/tar-dir
/data/tar-dir/dir
/data/tar-dir/dir/file1.txt
/data/tar-dir/dir/file2.txt
/data/tar-dir/file.txt
/data/file.txt

仅存在COPY和ADD中的文件。这样做的原因很容易看出,我们是否查看了docker用于RUN步骤的临时容器(这就是为什么我在构建期间拥有sleep 5m的原因)。这是那5分钟的睡眠期间另一个窗口的输出:

$ docker ps -l                         
CONTAINER ID        IMAGE               COMMAND                   CREATED             STATUS           PORTS               NAMES
d75794387274        3fc45f2e62a4        "/bin/sh -c 'echo \"h…"   1 second ago        Created                               brave_dubinsky

$ docker diff d75

$ docker inspect d75                                                                                                                                                                            
[                                                                                                                                                                                               
    {                                                                                                                                                                                           
        "Id": "d75794387274cc222391065c14581a29ff9fcc898ef367db64b9f145bd9325c7",                                                                                                               
        "Created": "2019-04-21T18:19:19.449392301Z",                                                                                                                                            
        "Path": "/bin/sh",                                                                                                                                                                      
        "Args": [                                                                                                                                                                               
            "-c",                                                                                                                                                                               
            "echo \"hello world\" >/data/run.txt  && find /data  && sleep 5m"                                                                                                                   
        ],                                                                                                                                                                                      
        "State": {                                                                                                                                                                              
            "Status": "running",       
            "Running": true,      
            "Paused": false,        
            "Restarting": false,                                                                    
            "OOMKilled": false,                                                                      
            "Dead": false,                     
            "Pid": 31620,                        
            "ExitCode": 0,            
            "Error": "",              
            "StartedAt": "2019-04-21T18:19:22.699031557Z",                         
            "FinishedAt": "0001-01-01T00:00:00Z"
        },                                            
        ...
        "Mounts": [
            {
                "Type": "volume",
                "Name": "07b9d30dfdfcae91b820dc6fa249030fd8d7a4ad9c50ee928aaab104c07c8a9d",
                "Source": "/home/var-docker/volumes/07b9d30dfdfcae91b820dc6fa249030fd8d7a4ad9c50ee928aaab104c07c8a9d/_data",
                "Destination": "/data",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
        ...

在以上命令中看到的是docker使用一个临时容器和一个匿名卷运行该构建。 diff输出显示对该容器的更改,该更改将被构建捕获为Dockerfile中的一层。在这种情况下,什么都没有。

对卷进行更改不会修改容器文件系统,因此您永远看不到更改,但是ADD和COPY命令直接针对图像层运行,因此您可以看到这些更改。

从Dockerfile中删除VOLUME是否可以解决此问题?可能不是(除非您运行映像的方法是从映像创建和重用匿名卷)。我是否仍建议删除VOLUME?是的,稍后不需要在运行容器时指定卷,可以为任何目录定义一个卷,然后在Dockerfile中中断尝试稍后使用RUN命令以非直观的方式扩展映像。


因此,如果不是VOLUME命令与您的COPY交互,为什么您还会看到所做的更改丢失?最可能的原因是运行容器时定义了一个卷。我们需要查看您的yml规格才能确定。该卷(如果是命名卷)将使用图像的内容初始化,但仅初始化一次。之后,无论您对映像进行什么更改,该卷都将保持不变,并从上次使用该卷起向您显示该卷中的文件。

如果要基于映像的更改来更新卷,则需要在映像中配置一个入口点,以将文件从映像中的保存位置复制到容器中的卷位置。我在docker-base图像中有执行此操作的示例。在此处查看save-volumeload-volume脚本。