浏览代码

Docker volume mounts

master
Chris Smith 5 年前
父节点
当前提交
4f30d8c7b9
共有 1 个文件被更改,包括 221 次插入0 次删除
  1. 221
    0
      site/content/post/2019-04-01-understanding-docker-volume-mounts.md

+ 221
- 0
site/content/post/2019-04-01-understanding-docker-volume-mounts.md 查看文件

@@ -0,0 +1,221 @@
1
+---
2
+date: 2019-04-01
3
+title: Understanding Docker volume mounts
4
+url: /2019/04/01/understanding-docker-volume-mounts/
5
+image: /res/images/docker/logo.png
6
+description: It's basically magic.
7
+---
8
+
9
+One thing that always confuses me with Docker is how exactly mounting
10
+volumes behaves. At a basic level it's fairly straight forward: you
11
+declare a volume in a Dockerfile, and then either explicitly mount
12
+something there or docker automatically creates an anonymous volume
13
+for you. Done. But it turns out there's quite a few edge cases...
14
+
15
+<!--more-->
16
+
17
+### Changing ownership of the folder
18
+
19
+Perhaps the most common operation done on a Docker volume other than
20
+simply mounting it is trying to change the ownership of the directory.
21
+If your Docker process runs as a certain user you probably want the
22
+directory to be writable by that user.
23
+
24
+At first we might try something like:
25
+
26
+{{< highlight docker >}}
27
+FROM alpine
28
+RUN adduser -D -u 1113 test123
29
+USER test123
30
+VOLUME /testing
31
+{{< / highlight >}}
32
+
33
+But changing the user doesn't seem to have any effect on the volume.
34
+Why? Checking the docs for the 
35
+[`USER` instruction](https://docs.docker.com/engine/reference/builder/#user)
36
+shows that only affects certain future operations -- namely
37
+`RUN`, `CMD`, and `ENTRYPOINT`. It doesn't affect the `VOLUME` instruction;
38
+if it did, you'd probably just get a permission denied error unless the user
39
+you switch to had privileges to create mount points.
40
+
41
+OK, so instead we might try using the good old `chown` command:
42
+
43
+{{< highlight docker >}}
44
+FROM alpine
45
+RUN adduser -D -u 1113 test123
46
+VOLUME /testing
47
+RUN chown test123 /testing
48
+{{< / highlight >}}
49
+
50
+But again, the directory is just owned by root at runtime.
51
+Back to the docs, this time for the
52
+[`VOLUME` instruction](https://docs.docker.com/engine/reference/builder/#volume)
53
+and towards the bottom is this little tidbit:
54
+
55
+> Changing the volume from within the Dockerfile: If any build steps change
56
+> the data within the volume after it has been declared, those changes will
57
+> be discarded.
58
+
59
+As soon as Docker hits `VOLUME` instruction, the directory becomes a mount
60
+point, and anything we do to the temporary volume mounted there is discarded
61
+during the build process. So we have to change the ownership *before* the
62
+instruction, which may seem a little counter-intuitive:
63
+
64
+{{< highlight docker >}}
65
+FROM alpine
66
+RUN adduser -D -u 1113 test123
67
+RUN mkdir /testing && chown test123 /testing
68
+VOLUME /testing
69
+{{< / highlight >}}
70
+
71
+Now when the container runs, the /testing directory is owned by the test123
72
+user. It's not quite over, yet, though. This works if we let Docker create
73
+a volume automatically for us, or if we create a named volume and mount that;
74
+if we try and mount a host directory, though, it falls flat:
75
+
76
+{{< highlight console >}}
77
+$ docker run --rm -it -v "$PWD/testing:/testing" testing ls -al /testing
78
+total 8
79
+drwxr-xr-x    2 1000     1000          4096 Apr  1 19:39 .
80
+drwxr-xr-x    1 root     root          4096 Apr  1 20:44 ..
81
+{{< / highlight >}}
82
+
83
+Docker handles mounting host directories differently to mounting volumes,
84
+even though the syntax is basically the same. Host directories are bind
85
+mounted directly into the container, so the permissions and ownership
86
+are the same as the directory on your host. The only way to fix them are
87
+to either change the permissions on the host, or have the container
88
+change them at runtime (assuming it has sufficient privileges).
89
+
90
+One final wrinkle in all this happens when you use the same container
91
+in multiple containers. Here we have two images built from the
92
+Dockerfile above, one with userid 1113 and one with userid 1114:
93
+
94
+{{< highlight console >}}
95
+$ docker volume create testing
96
+testing
97
+
98
+$ docker run --rm -it -v testing:/testing testing1113 ls -nal /testing
99
+total 8
100
+drwxr-xr-x    2 1113     0             4096 Apr  1 19:49 .
101
+drwxr-xr-x    1 0        0             4096 Apr  1 20:51 ..
102
+
103
+$ docker run --rm -it -v testing:/testing testing1114 ls -nal /testing
104
+total 8
105
+drwxr-xr-x    2 1114     0             4096 Apr  1 20:47 .
106
+drwxr-xr-x    1 0        0             4096 Apr  1 20:52 ..
107
+
108
+$ docker run --rm -it -v testing:/testing testing1114 touch /testing/Hello
109
+
110
+$ docker run --rm -it -v testing:/testing testing1113 ls -nal /testing
111
+total 8
112
+drwxr-xr-x    2 1114     0             4096 Apr  1 20:52 .
113
+drwxr-xr-x    1 0        0             4096 Apr  1 20:53 ..
114
+-rw-r--r--    1 0        0                0 Apr  1 20:52 Hello
115
+
116
+$ docker run --rm -it -v testing:/testing testing1114 ls -nal /testing
117
+total 8
118
+drwxr-xr-x    2 1114     0             4096 Apr  1 20:52 .
119
+drwxr-xr-x    1 0        0             4096 Apr  1 20:52 ..
120
+-rw-r--r--    1 0        0                0 Apr  1 20:52 Hello
121
+{{< / highlight >}}
122
+
123
+Can you see what's going on? When the volume is empty, the ownership
124
+changes based on the mount point in the container. Once it has something
125
+in it, the ownership is fixed.
126
+
127
+So Docker behaves differently with regard to permissions:
128
+
129
+ * when the folder is mounted from the host vs a volume
130
+ * when the volume is empty vs having content
131
+
132
+### Pre-populating mounts with files from the image
133
+
134
+One of the more esoteric features of the way Docker handles volume
135
+mounts is that in some cases files from the image are copied over
136
+into the container. For example:
137
+
138
+{{< highlight console >}}
139
+$ docker volume create testing
140
+testing
141
+
142
+$ docker run --rm -it -v testing:/etc testing sleep 1
143
+
144
+$ docker run --rm -it -v testing:/tmp testing ls -al /tmp
145
+total 184
146
+drwxr-xr-x   15 root     root          4096 Apr  1 20:58 .
147
+drwxr-xr-x    1 root     root          4096 Apr  1 20:59 ..
148
+-rw-r--r--    1 root     root             4 Jun  7  2018 TZ
149
+-rw-r--r--    1 root     root             6 Dec 20 21:31 alpine-release
150
+...
151
+{{< / highlight >}}
152
+
153
+The first container we run mounts the newly created `testing` volume
154
+at `/etc`. Docker copies all the existing files and folders into the
155
+volume; when we then run the second container with the volume mounted
156
+at `/tmp`, we can see all of the files that were in the first container's
157
+`/etc`.
158
+
159
+As with permissions, this behaviour is anything but consistent. Say we
160
+switch from a volume to a host directory:
161
+
162
+{{< highlight console >}}
163
+$ mkdir testing
164
+$ docker run --rm -it -v "$PWD/testing:/usr/bin" testing sleep 1
165
+$ ls -al testing
166
+total 8
167
+drwxr-xr-x 2 root  root  4096 Apr  1 22:05 .
168
+drwxr-xr-x 3 chris chris 4096 Apr  1 22:05 ..
169
+{{< / highlight >}}
170
+
171
+Nothing is copied in, and inside the container the folder will be empty.
172
+Based on our discoveries with permisions, it's reasonable to assume the
173
+same will happy with a non-empty volume too:
174
+
175
+{{< highlight console >}}
176
+$ docker volume create testing
177
+testing
178
+
179
+$ docker run --rm -it -v testing:/testing testing touch /testing/Hello
180
+
181
+$ docker run --rm -it -v testing:/usr/bin testing sleep 1
182
+
183
+$ docker run --rm -it -v testing:/tmp testing ls -al /tmp
184
+total 8
185
+drwxr-xr-x    2 root     root          4096 Apr  1 21:09 .
186
+drwxr-xr-x    1 root     root          4096 Apr  1 21:09 ..
187
+-rw-r--r--    1 root     root             0 Apr  1 21:08 Hello
188
+{{< / highlight >}}
189
+
190
+So at least that's consistent. If you're very observant, though, you
191
+might notice I switched from `/etc/` to `/usr/bin` in the examples.
192
+That's because within the container `/etc/` has some files bind-mounted
193
+into it, such as `/etc/resolv.conf`, and these *do* always result in files
194
+being created in the mounted volumes or folders:
195
+
196
+{{< highlight console >}}
197
+$ mkdir testing
198
+$ docker run --rm -it -v "$PWD/testing:/etc" testing sleep 1
199
+$ ls -al testing
200
+total 8
201
+drwxr-xr-x 2 chris chris 4096 Apr  1 22:12 .
202
+drwxr-xr-x 3 chris chris 4096 Apr  1 22:12 ..
203
+-rwxr-xr-x 1 root  root     0 Apr  1 22:12 hostname
204
+-rwxr-xr-x 1 root  root     0 Apr  1 22:12 hosts
205
+-rwxr-xr-x 1 root  root     0 Apr  1 22:12 resolv.conf
206
+{{< / highlight >}}
207
+
208
+### Summary
209
+
210
+ * Docker treats mounting host folders and mounting volumes differently.
211
+   Don't just assume that you can swap one for another and get the exact
212
+   same behaviour.
213
+ * Empty volumes will inherit permissions and files from the image
214
+   they are mounted in; non-empty volumes and host folders will not.
215
+ * Relying on Docker copying files into volumes is a very bad idea,
216
+   as if you change those files in a future version of your image
217
+   they will not be copied unless the volume is deleted and
218
+   recreated.
219
+
220
+I can't find anywhere that these points are documented properly;
221
+if you know of anywhere, please drop me a message!

正在加载...
取消
保存