《自己动手写Docker》书摘之三---Union File System介绍

2023-05-16

Union File System

UnionFS

unionfs是一种为Linux,FreeBSD和NetBSD操作系统设计的把其他文件系统联合到一个联合挂载点的文件系统服务。它使用branch把不同文件系统的文件和目录“透明地”覆盖,形成一个单一一致的文件系统。这些branches或者是read-only或者是read-write的,所以当对这个虚拟后的联合文件系统进行写操作的时候,系统是真正写到了一个新的文件中。看起来这个虚拟后的联合文件系统是可以对任何文件进行操作的,但是其实它并没有改变原来的文件,这是因为unionfs用到了一个重要的资管管理技术叫写时复制。
写时复制(copy-on-write,下文简称CoW),也叫隐式共享,是一种对可修改资源实现高效复制的资源管理技术。它的思想是,如果一个资源是重复的,但没有任何修改,这时候并不需要立即创建一个新的资源;这个资源可以被新旧实例共享。创建新资源发生在第一次写操作,也就是对资源进行修改的时候。通过这种资源共享的方式,可以显著地减少未修改资源复制带来的消耗,但是也会在进行资源修改的时候增减小部分的开销。
用一个经典的例子来解释一下,Knoppix,一个用于Linux演示、光盘教学和商业产品演示的Linux发行版,就是把一个CD-ROM或者DVD和一个存在在可读写设备(eg,U盘)上的叫knoppix.img的文件系统联合起来。这样任何对CD/DVD上文件的改动都会在被应用在U盘上,不改变原来的CD/DVD上的内容。

AUFS

AUFS,英文全称是Advanced multi-layered unification filesystem, 曾经也叫 Acronym multi-layered unification filesystem,Another multi-layered unification filesystem。AUFS完全重写了早期的UnionFS 1.x,其主要目的是为了可靠性和性能,并且引入了一些新的功能,比如可写分支的负载均衡。AUFS的一些实现已经被纳入UnionFS 2.x版本。

Docker是如何使用AUFS的

AUFS是Docker选用的第一种存储驱动。AUFS具有快速启动容器,高效利用存储和内存的优点,直到现在AUFS仍然是Docker支持的一种存储驱动类型。接下来我们要介绍Docker是如何利用AUFS存储images和containers的。

image layer和AUFS

每一个Docker image都是由一系列的read-only layers组成。image layers的内容都存储在Docker hosts filesystem的/var/lib/docker/aufs/diff目录下。而/var/lib/docker/aufs/layers目录则存储着image layer如何堆栈这些layer的metadata。
准备一台安装了Docker 1.11.2的ECS。在没有拉取任何镜像,启动任何容器的情况下,执行ls /var/lib/docker/aufs/diff命令,发现目录没有存储任何内容。拉取Ubuntu:15.04镜像,然后再次执行ls /var/lib/docker/aufs/diff命令。我们可以看到在docker pull的结果显示ubuntu:15.04镜像一共有4个layers,在执行ls /var/lib/docker/aufs/diff命令的结果中也有四个对应的存储文件目录。这里有一点需要说明的是,自从Docker 1.10之后,diff目录下的存储镜像layer文件夹不再与镜像ID相同。最后cat /var/lib/docker/aufs/layers/6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea命令列出来的是堆栈里位于6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea layer下方的layers。

$ docker pull ubuntu:15.04
15.04: Pulling from library/ubuntu
9502adfba7f1: Pull complete
4332ffb06e4b: Pull complete
2f937cc07b5f: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:2fb27e433b3ecccea2a14e794875b086711f5d49953ef173d8a03e8707f1510f
Status: Downloaded newer image for ubuntu:15.04

$ ls /var/lib/docker/aufs/diff
208319b22189a2c3841bc4a4ef0df9f9238a3e832dc403133fb8ad4a6c22b01b  9c444e426a4a0aa3ad8ff162dd7bcd4dcbb2e55bdec268b24666171904c17573
6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea  f193107618deb441376a54901bc9115f30473c1ec792b7fb3e73a98119e2cf77

$ ls /var/lib/docker/aufs/mnt
208319b22189a2c3841bc4a4ef0df9f9238a3e832dc403133fb8ad4a6c22b01b  9c444e426a4a0aa3ad8ff162dd7bcd4dcbb2e55bdec268b24666171904c17573
6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea  f193107618deb441376a54901bc9115f30473c1ec792b7fb3e73a98119e2cf77

$ cat /var/lib/docker/aufs/layers/6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea
9c444e426a4a0aa3ad8ff162dd7bcd4dcbb2e55bdec268b24666171904c17573
f193107618deb441376a54901bc9115f30473c1ec792b7fb3e73a98119e2cf77
208319b22189a2c3841bc4a4ef0df9f9238a3e832dc403133fb8ad4a6c22b01b

接下来我们要以ubuntu:15.04镜像为基础镜像,创建一个名为changed-ubuntu的镜像。这个镜像只是在镜像的/tmp文件夹中添加一个写了“Hello world”的文件。你可以使用下面的Dockerfile来实现:

 FROM ubuntu:15.04

 RUN echo "Hello world" > /tmp/newfile

在terminal中cd到上面Dockerfile所在位置,执行docker build -t changed-ubuntu .命令来build镜像。

$docker build -t changed-ubuntu .
Sending build context to Docker daemon 10.75 kB
Step 1 : FROM ubuntu:15.04
 ---> d1b55fd07600
Step 2 : RUN echo "Hello world" > /tmp/newfile
 ---> Running in c72100f81dd1
 ---> 9d8602c9aee1
Removing intermediate container c72100f81dd1
Successfully built 9d8602c9aee1

然后执行docker images查看现在的镜像,可以看到新生成的changed-ubuntu。

$docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
changed-ubuntu      latest              9d8602c9aee1        About a minute ago   131.3 MB
ubuntu              15.04               d1b55fd07600        10 months ago        131.3 MB

使用docker history changed-ubuntu命令可以清楚地查看到changed-ubuntu镜像使用了哪些image layers。从输出中可以看到9d8602c9aee1 image layer位于最上层,只有12B的大小,就是由/bin/sh -c echo “Hello world” > /tmp/newfile命令创建的。也就是说changed-ubuntu镜像只占用了12Bytes的磁盘空间,这也证明了AUFS是如何高效使用磁盘空间的。而下面的四层image layers则是共享的构成ubuntu:15.04镜像的4个image layers。“missing”标记的layers是自Docker 1.10之后,一个镜像的image layers的image history数据都存储在一个文件中导致,这是一个Docker官方认为的正常行为。

$docker history changed-ubuntu
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
9d8602c9aee1        4 minutes ago       /bin/sh -c echo "Hello world" > /tmp/newfile    12 B
d1b55fd07600        10 months ago       /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B
<missing>           10 months ago       /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.879 kB
<missing>           10 months ago       /bin/sh -c echo '#!/bin/sh' > /usr/sbin/polic   701 B
<missing>           10 months ago       /bin/sh -c #(nop) ADD file:3f4708cf445dc1b537   131.3 MB

接下来我们继续查看layers的存储信息,从输出中我们可以看到/var/lib/docker/aufs/diff目录和/var/lib/docker/aufs/mnt目录均多了一个文件夹9f122dbaa103338f27bac146326af38a2bcb52f98ebb3530cac828573faa3c4e。当使用cat /var/lib/docker/aufs/layers/9f122dbaa103338f27bac146326af38a2bcb52f98ebb3530cac828573faa3c4e命令来查看它的metadata时可以看到,它前面的layers就是ubuntu:15.04镜像所使用的4个image layers。进一步的探查/var/lib/docker/aufs/diff/9f122dbaa103338f27bac146326af38a2bcb52f98ebb3530cac828573faa3c4e文件夹,发现其中存储了一个/tmp/newfile文件,文件中只有一行“Hello world”。至此,我们完整地分析出了image layer和AUFS是如何通过共享文件和文件夹来实现镜像存储的。

$ ls /var/lib/docker/aufs/diff
208319b22189a2c3841bc4a4ef0df9f9238a3e832dc403133fb8ad4a6c22b01b  9c444e426a4a0aa3ad8ff162dd7bcd4dcbb2e55bdec268b24666171904c17573  f193107618deb441376a54901bc9115f30473c1ec792b7fb3e73a98119e2cf77
6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea  9f122dbaa103338f27bac146326af38a2bcb52f98ebb3530cac828573faa3c4e

$ ls /var/lib/docker/aufs/mnt
208319b22189a2c3841bc4a4ef0df9f9238a3e832dc403133fb8ad4a6c22b01b  9c444e426a4a0aa3ad8ff162dd7bcd4dcbb2e55bdec268b24666171904c17573  f193107618deb441376a54901bc9115f30473c1ec792b7fb3e73a98119e2cf77
6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea  9f122dbaa103338f27bac146326af38a2bcb52f98ebb3530cac828573faa3c4e

$ cat /var/lib/docker/aufs/layers/9f122dbaa103338f27bac146326af38a2bcb52f98ebb3530cac828573faa3c4e
6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea
9c444e426a4a0aa3ad8ff162dd7bcd4dcbb2e55bdec268b24666171904c17573
f193107618deb441376a54901bc9115f30473c1ec792b7fb3e73a98119e2cf77
208319b22189a2c3841bc4a4ef0df9f9238a3e832dc403133fb8ad4a6c22b01b

$ cat /var/lib/docker/aufs/diff/9f122dbaa103338f27bac146326af38a2bcb52f98ebb3530cac828573faa3c4e/tmp/newfile
Hello world

container layer和AUFS

Docker使用AUFS的CoW技术来实现image layer共享和减少磁盘空间占用。CoW意味着一旦某个文件只有很小的部分有改动,AUFS也需要复制整个文件。这种设计会对容器性能产生一定的影响,尤其是在待拷贝的文件很大,或者位于很多image layers的下方,或AUFS需要深度搜索目录结构树的时候。不过也不用过度担心,对于一个容器,每一个image layer最多只需要拷贝一次。后续的改动都会在第一次拷贝的container layer上进行。
启动一个Container的时候,Docker会为其创建一个read-only的init layer,用来存储与这个容器内环境相关的内容;Docker还会为其创建一个read-write的layer用来执行所有写操作。
Container layer的mount目录也是/var/lib/docker/aufs/mnt。Container的metadata和配置文件都存放在/var/lib/docker/containers/目录中。Container的read-write layer存储在/var/lib/docker/aufs/diff/目录下。即使容器停止,这个可读写层仍然存在,因而重启容器不会丢失数据,只有当一个容器被删除的时候,这个可读写层才会一起删除。
接下来我们仍然用实验来证明上面的结论。首先查询现有的容器数目为0,而且在/var/lib/docker/containers目录下也没有查到任何数据。最后,查看下系统的aufs mount情况,只有一个config文件。

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

$ ls /var/lib/docker/containers

$ ls /sys/fs/aufs/

启动一个changed-ubuntu的容器。

$docker run -dit changed-ubuntu bash
fb5939d878bb0521008d63eb06adea75e6af275855f11879dfa3992dfdaa5e3f

$docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
fb5939d878bb        changed-ubuntu      "bash"              28 seconds ago      Up 27 seconds                           amazing_babbage

查看/var/lib/docker/aufs/diff目录发现,下面多了两个文件夹,f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8就是Docker为容器创建的read-write layer,而f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8-init则是Docker为容器创建的read-only的init layer。

$ ls /var/lib/docker/aufs/diff
208319b22189a2c3841bc4a4ef0df9f9238a3e832dc403133fb8ad4a6c22b01b  9f122dbaa103338f27bac146326af38a2bcb52f98ebb3530cac828573faa3c4e  f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8-init
6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea  f193107618deb441376a54901bc9115f30473c1ec792b7fb3e73a98119e2cf77
9c444e426a4a0aa3ad8ff162dd7bcd4dcbb2e55bdec268b24666171904c17573  f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8

/var/lib/docker/aufs/mnt目录的变化和/var/lib/docker/aufs/diff一致。

$ ls /var/lib/docker/aufs/mnt
208319b22189a2c3841bc4a4ef0df9f9238a3e832dc403133fb8ad4a6c22b01b  9f122dbaa103338f27bac146326af38a2bcb52f98ebb3530cac828573faa3c4e  f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8-init
6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea  f193107618deb441376a54901bc9115f30473c1ec792b7fb3e73a98119e2cf77
9c444e426a4a0aa3ad8ff162dd7bcd4dcbb2e55bdec268b24666171904c17573  f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8

/var/lib/docker/aufs/layers/目录下多了与上文两个文件目录同名的文件,用cat命令可以清楚地看到其依赖layer的记录。

$ls /var/lib/docker/aufs/layers
208319b22189a2c3841bc4a4ef0df9f9238a3e832dc403133fb8ad4a6c22b01b  9f122dbaa103338f27bac146326af38a2bcb52f98ebb3530cac828573faa3c4e  f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8-init
6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea  f193107618deb441376a54901bc9115f30473c1ec792b7fb3e73a98119e2cf77
9c444e426a4a0aa3ad8ff162dd7bcd4dcbb2e55bdec268b24666171904c17573  f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8

$ cat /var/lib/docker/aufs/layers/f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8
f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8-init
9f122dbaa103338f27bac146326af38a2bcb52f98ebb3530cac828573faa3c4e
6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea
9c444e426a4a0aa3ad8ff162dd7bcd4dcbb2e55bdec268b24666171904c17573
f193107618deb441376a54901bc9115f30473c1ec792b7fb3e73a98119e2cf77
208319b22189a2c3841bc4a4ef0df9f9238a3e832dc403133fb8ad4a6c22b01b

$ cat /var/lib/docker/aufs/layers/f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8-init
9f122dbaa103338f27bac146326af38a2bcb52f98ebb3530cac828573faa3c4e
6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea
9c444e426a4a0aa3ad8ff162dd7bcd4dcbb2e55bdec268b24666171904c17573
f193107618deb441376a54901bc9115f30473c1ec792b7fb3e73a98119e2cf77
208319b22189a2c3841bc4a4ef0df9f9238a3e832dc403133fb8ad4a6c22b01b

在/var/lib/docker/containers/目录下新建一个与containerid相同的文件夹,存放着容器的metadata和config文件。

$ ls /var/lib/docker/containers/
fb5939d878bb0521008d63eb06adea75e6af275855f11879dfa3992dfdaa5e3f

$ ls /var/lib/docker/containers/fb5939d878bb0521008d63eb06adea75e6af275855f11879dfa3992dfdaa5e3f/
config.v2.json  fb5939d878bb0521008d63eb06adea75e6af275855f11879dfa3992dfdaa5e3f-json.log  hostconfig.json  hostname  hosts  resolv.conf  resolv.conf.hash  shm

接下来我们从系统aufs来看mount的情况,在/sys/fs/aufs/目录下多了一个si_fe6d5733e85e4904文件夹。通过cat /sys/fs/aufs/si_fe6d5733e85e4904/*命令我们可以清楚地看到这就是我们刚刚起的容器的layer权限,只有最上面的f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8 layer是read-write权限。

$s /sys/fs/aufs/
config  si_fe6d5733e85e4904

$ cat /sys/fs/aufs/si_fe6d5733e85e4904/*
/var/lib/docker/aufs/diff/f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8=rw
/var/lib/docker/aufs/diff/f9ccf5caa9b7324f0ef112750caa14203b557d276ca08c78c23a42a949e2bfc8-init=ro+wh
/var/lib/docker/aufs/diff/9f122dbaa103338f27bac146326af38a2bcb52f98ebb3530cac828573faa3c4e=ro+wh
/var/lib/docker/aufs/diff/6bb19cb345da470e015ba3f1ca049a1c27d2c57ebc205ec165d2ad8a44e148ea=ro+wh
/var/lib/docker/aufs/diff/9c444e426a4a0aa3ad8ff162dd7bcd4dcbb2e55bdec268b24666171904c17573=ro+wh
/var/lib/docker/aufs/diff/f193107618deb441376a54901bc9115f30473c1ec792b7fb3e73a98119e2cf77=ro+wh
/var/lib/docker/aufs/diff/208319b22189a2c3841bc4a4ef0df9f9238a3e832dc403133fb8ad4a6c22b01b=ro+wh
64
65
66
67
68
69
70
/run/shm/aufs.xino

最后提下AUFS如何为Container删除一个文件。如果要删除file1,AUFS会在container的read-write层生成一个.wh.file1的文件来隐藏所有read-only层的file1文件。至此,我们已清楚地描述和验证了Docker是如何使用AUFS来管理container layers的。

自己动手写AUFS

下面我们自己动手用简单的命令来创建一个AUFS文件系统,感受下如何使用AUFS和CoW实现文件管理。
首先在你的实验目录下创建一个aufs的文件夹,然后在aufs目录下创建一个mnt的文件夹做过挂载点。接着在aufs目录下创建一个叫container-layer的文件夹,里面有一个名为container-layer.txt的文件,文件内容为I am container layer。同样地,继续在aufs目录下创建4个名为image-layer nn1 4imagelayer {n}.txt的文件,文件内容为I am image layer${n}。使用如下命令检查文件内容:

$ cd /home/qinyujia/aufs

$ ls
container-layer  image-layer1  image-layer2  image-layer3  image-layer4  mnt

$ cat container-layer.txt
I am container layer

$ cat image-layer1/image-layer1.txt
I am image layer 1

$cat image-layer2/image-layer2.txt
I am image layer 2

$ cat image-layer3/image-layer3.txt
I am image layer 3

$ cat image-layer4/image-layer4.txt
I am image layer 4

要联合的文件目录都已经准备好了,接下来我们把container-layer和4个名为image-layer${n}的文件夹使用aufs的方式来挂载到刚刚创建的mnt目录下。在mount aufs的命令中,我们没有指定待挂载的5个文件夹的权限,默认行为是,dirs指定的左边起第一个目录是read-write权限,后续的都是read-only权限。

$ sudo mount -t aufs -o dirs=./container-layer:./image-layer4:./image-layer3:./image-layer2:./image-layer1 none ./mnt

$ tree mnt
mnt
├── container-layer.txt
├── image-layer1.txt
├── image-layer2.txt
├── image-layer3.txt
└── image-layer4.txt

大家还记得上文中我们曾经在系统aufs目录下去查看文件的读写权限吗?这里我们依然使用cat /sys/fs/aufs/si_fe6d5733e85e5904/* 命令来确认新mount的文件系统中每个目录的权限。(注意si_fe6d5733e85e5904应该是系统为这个mnt挂载点新创建的,而非在介绍Docker和AUFS里面提到的那个文件夹)根据输出我们可以清楚地看到,只有container-layer文件夹是read-write的,其余都是read-only权限。

$ cat /sys/fs/aufs/si_fe6d5733e85e5904/*
/home/qinyujia/aufs/container-layer=rw
/home/qinyujia/aufs/image-layer4=ro
/home/qinyujia/aufs/image-layer3=ro
/home/qinyujia/aufs/image-layer2=ro
/home/qinyujia/aufs/image-layer1=ro
64
65
66
67
68
/home/qinyujia/aufs/container-layer/.aufs.xino

下面我们要执行一个有意思的操作,往mnt/image-layer1.txt文件末尾添加一行文字“write to mnt’s image-layer1.txt”。根据上面我们介绍的CoW技术,大家猜想下会产生什么样的行为。

$ echo -e "\nwrite to mnt's image-layer1.txt" >> ./mnt/image-layer4.txt

我们用cat命令去查看mnt/image-layer4.txt文件内容,发现内容确实从“I am image layer 4”变成了
“I am image layer 4

write to mnt’s image-layer1.txt”,因为mnt只是一个虚拟挂载点,因为我们继续去寻找文件到底修改在了什么位置。

$ cat ./mnt/image-layer4.txt
I am image layer 4

write to mnt's image-layer1.txt

我们查看image-layer4/image-layer4.txt文件内容,发现其并未改变。

$ cat image-layer4/image-layer4.txt
I am image layer 4

接下来,当我们检查container-layer文件夹的时候,发现多了一个名为image-layer4.txt的文件,文件的内容是
“I am image layer 4

write to mnt’s image-layer1.txt”。也就是当我们尝试向mnt/image-layer4.txt文件进行写操作的时候,系统首先在mnt目录下查找名为image-layer4.txt的文件,将其拷贝到read-write层的container-layer目录中,接着对container-layer目录中的image-layer4.txt文件进行写操作。到此,我们成功地完成了一个小小的demo,实现了自己的AUFS文件系统。

$ ls container-layer/
container-layer.txt  image-layer4.txt

$cat container-layer/image-layer4.txt
I am image layer 4

write to mnt's image-layer1.txt

相关图书推荐<<自己动手写 docker>>

这里写图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

《自己动手写Docker》书摘之三---Union File System介绍 的相关文章

  • 从文件中获取InputStream,该文件可能位于(或不位于)类路径中[重复]

    这个问题在这里已经有答案了 只是想知道哪种方法是读取类路径中的文件的最佳方法 我唯一拥有的是带有文件路径的属性 举个例子 文件路径 类路径 com mycompany myfile txt 文件路径 文件 myfolder myfile t
  • python:PyPi公共模块:如何确定是否安全?

    我已经完成了我的 python 3 应用程序 它正在使用 PyPi 的多个公共模块 然而 在我将其部署到我公司的企业 将处理客户的凭据并访问第 3 方 API 之前 我需要尽职调查确保它们既安全又安全 我必须执行哪些步骤 验证 PyPi 模
  • 如何检查docker中当前/默认的日志驱动程序?

    我正在尝试检查已停止的 docker 容器的日志 但是当我这样做时docker logs
  • 在docker中使用MySQL数据库设置aspnetcore

    我正在尝试设置一个 docker compose 文件 其中包含 asp net core mysql 数据库和 phpmyadmin 的容器 设置我的 mysql 服务器没有问题 我可以使用 phpmyadmin 访问它 我的 asp n
  • .bat 文件将文件排序到文件夹中

    对于我的图片集 我希望文件夹中的所有图片按日期自动分类到文件夹中 幸运的是 这些文件已经以时间戳命名 2012 07 15 12 21 06 jpg 2012 07 15 12 21 26 jpg 2012 07 16 12 12 50 j
  • 在 Docker 容器中看不到 Django

    我想在一个简单的 Docker 容器中运行 Django 首先 我使用 Docker 文件构建了容器 里面没有什么特别的 只有 FROM RUN 和 COPY 命令 然后我用命令运行我的容器 docker run tid p 8000 80
  • 保存录制的 AVAudioRecorder 声音文件:现在怎么办? (iOS、Xcode 4)

    在我的应用程序中 我希望用户能够录制一个声音文件并播放它 然后保存该声音文件以供以后使用 我用了本教程 http www techotopia com index php Recording Audio on an iPhone with
  • 拒绝访问特定目录中的特定文件类型

    对于某些应用程序 用户可以上传自己的文件 由于这可能是非常大的文件 因此他们可以通过自己的 FTP 客户端上传这些文件 当然 我不希望他们上传一些可以访问服务器上所有其他文件的 PHP 文件 我想要防止这种行为的方法之一是拒绝仅访问这些文件
  • 无法使用 docker build 运行 gradle 包装器

    我有这个小构建 FROM eclipse temurin 17 jdk as build java COPY java project root project WORKDIR root project RUN chmod x gradle
  • docker build 如何知道 Dockerfile RUN 或 COPY 行是否可以使用缓存?

    如果我的 Python 项目的 Dockerfile 如下所示 FROM python 3 7 Set env variables ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1 S
  • Java:如何从转义的 URL 获取文件?

    我收到了一个定位本地文件的 URL 事实上我收到的 URL 不在我的控制范围内 URL 按照 RFC2396 中的定义进行有效转义 如何将其转换为 Java File 对象 有趣的是 URL getFile 方法返回一个字符串 而不是文件
  • 删除文件的最后 10 个字符

    我想删除文件的最后 10 个字符 说一个字符串 hello i am a c learner 是文件内的数据 我只是希望该文件是 hello i am a 文件的最后 10 个字符 即字符串 c learner 应在文件内消除 解决方案 将
  • 经常提交 docker 容器是一个好习惯吗?

    我在里面使用WebSphere Liberty 由于 WebSphere Liberty 需要频繁的 xml 编辑 这对于 Dockerfile 命令来说是不可能的 我必须不时地对容器进行 docker commit 以便其他人可以使用我的
  • 带有 npm 启动脚本的 Nodejs 应用程序

    我对nodejs很陌生 在我的docker化环境中 我想为nodejs应用程序提供appdynamics支持 这要求每个应用程序都要求将以下内容作为其应用程序的第一行 require appdynamics profile controll
  • JavaFX ImageView 未更新

    因此 我尝试将图像加载并保存到 imageView 中 其中图像的位置是通过文件浏览器选择的 我已经为此工作好几天了 如果我不能解决这个问题 我就会中风 我已经尝试了我能想到的一切 预先感谢您的帮助 UPDATED 这是我的主要课程 pub
  • 如何计算最低系统要求?

    对于我用 Visual C 编写的应用程序 Testing 不 真的 这就是全部
  • 从文件 C 中的单行读取多个变量类型

    好吧 我一整天都在做这个 但我一辈子都无法把它记下来 也许你们可以帮忙 我有一个文件 内容如下 1301 105515018 水手长 迈克尔 R ABC 123 R01 1301 103993269 卡斯蒂利亚 小迈克尔 ABC 123 R
  • 无法访问 res 文件夹?

    我有一个 Java 编程问题 需要帮助 我的类文件位于单独的包中 不是默认包 我正在尝试从我的 res 文件夹访问文件 我已将其添加为类文件夹 使用属性 gt 库 gt 添加类文件夹 在我的类中 我有以下代码 InputStream IS
  • 使用 docker for windows 工具箱切换到 Windows 容器

    我已经在 Windows 7 64 位操作系统上安装了 docker for windows toolbox 我无法使用 docker 菜单切换到 Windows 容器 因为 docker 图标在系统托盘中不可用 Docker 服务也不可用
  • 将变量写入 Ansible 中的文件

    我通过 URI 模块提取 JSON 并希望将接收到的内容写入文件 我能够获取内容并将其输出到调试器 因此我知道已收到内容 但我不知道写入文件的最佳实践 来自的重要评论tmoschou https stackoverflow com user

随机推荐