1 -v 目录映射
在主机的”/home/admin/dev/aaa“目录和docker中的目录/data 建立map 关系:
$ docker run -it --name 'faltomcat-vim' -v /home/admin/dev/aaa:/data faltomcat-vim bash
2 Volumn 数据卷
数据卷的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的 数据卷。
在用 docker run 命令的时候,使用 --mount
标记来将 数据卷 挂载到容器里。在一次 docker run 中可以挂载多个 数据卷。
// 创建数据卷my-vol docker volume create my-vol // 启动一个挂载数据卷的容器,target是容器中的路径。 docker run --mount source=my-vol,target=/webapp nginx // 查看所有数据卷 docker volume ls // 查看指定数据卷的信息 docker volume inspect my-vol // 删除指定数据卷 docker volume rm my-vol // 无主的数据卷可能会占据很多空间,使用这条命令可以清理掉 docker volume prune
对于CentOS7,宿主主机volumn目录再:/var/lib/docker/volumes/。
经测试,如果手工删除了 volumn 映射的目录,重启 swarm 的 service 是不会成功的,需要先重启docker才行,如:service docker restart。
3 Dockerfile 中的 VOLUME 与 -v 使用注意
4 提前创建Volumn供Swarm Compose使用
以某项目为例,在执行Dockerfile文件时候,我们使用了COPY/ADD/RUN等命令来创建目录或拷贝文件:
这里compose会自己创建volumn,在多数情况是没问题的。但我们现在有个需求,客户在部署我们的镜像时,需要让他更改系统默认的 hostIP 127.0.0.1,不更改就只能本机访问。若想避免客户每次都去 /volumns/falpolicy_falhome/_data/falpolicy/config/application.properties 中改的话,可以写个脚本,提前创建Volumn,命令:docker volume create falhome。一旦提前创建volumn后,这个Dockfile里红框框圈出来的命令就不会再被执行了,即无法拷贝和创建子目录了在这个volumn里。这可以通过将 mkdir 命令放 entrypoint.sh 中,或者在刚才创建volumn的脚本中来创建。下面提供两种方案具体实现。
4.1 方案1:docker service 还没跑起来就提前先创建 docker volumn
- 首次运行 startup.sh,输入IP存储到startup.sh所在目录的 application.properties;第二次调用startup.sh 不让输入IP,若要改IP请直接执行改IP脚本。
- 然后创建 docker volumn ,建立 application.properties 所在的目录,并将 application.properties 拷贝进去。
- load and run images.
下面是我自己写的 Linux Shell 脚本,set-falpolicy-host-ip.sh:
#!/bin/bash f () { errcode=$? # save the exit code as the first thing done in the trap function echo "==================================================" echo "error $errorcode" echo "the command executing at the time of the error was" echo "$BASH_COMMAND" echo "on line ${BASH_LINENO[0]}" echo "==================================================" # do some error handling, cleanup, logging, notification # $BASH_COMMAND contains the command that was being executed at the time of the trap # ${BASH_LINENO[0]} contains the line number in the script of that command # exit the script or return to try again, etc. exit $errcode # or use some other value or do return instead } trap f ERR checkRootPrivileges() { if [ $UID -ne 0 ]; then echo ">>> 运行此脚本需要管理员权限。" echo ">>> e.g. \"sudo $0\"" exit 1 fi } checkRootPrivileges # 设置 application.properties 文件路径,值存放在 APP_PROP_FILE 变量中。 APP_PROP_FILE='./application.properties' setAppPropFile() { if [ ! -f $APP_PROP_FILE ];then APP_PROP_FILE='./tool/application.properties' fi } setAppPropFile # 获取服务器访问IP,值存放在 POLICY_ACCESS_HOST_VALUE 变量中。 POLICY_ACCESS_HOST_VALUE="" getServerHostIP() { POLICY_ACCESS_HOST_VALUE=`cat $1 | grep ${POLICY_ACCESS_HOST_KEY} |awk '{print substr($1,31)}'` } setServerHostIP () { read -p "请输入 FalPolicy 服务器访问IP: " HOST_IP if [ ! -n "$HOST_IP" ] ;then echo "FalPolicy 服务器访问IP 输入有误,2秒后自动退出。" sleep 2 exit else echo ">>> 您输入的 FalPolicy 服务器访问IP: $HOST_IP" fi getServerHostIP ${APP_PROP_FILE} SOURCE_TEXT="fal.policy.server.access.host=${POLICY_ACCESS_HOST_VALUE}" TARGET_TEXT="fal.policy.server.access.host=${HOST_IP}" sed -i "s/${SOURCE_TEXT}/${TARGET_TEXT}/g" `grep ${SOURCE_TEXT} -rl ${APP_PROP_FILE}` getServerHostIP ${APP_PROP_FILE} echo ">>> 更改后的 FalPolicy 服务器访问IP: ${POLICY_ACCESS_HOST_VALUE}" echo ">>> docker volume create" $FALPOLICY_HOME_VOLUMN docker volume create $FALPOLICY_HOME_VOLUMN if [ ! -d $VOLUMN_APP_PROP_DIR ];then echo ">>> mkdir -p" $VOLUMN_APP_PROP_DIR mkdir -p $VOLUMN_APP_PROP_DIR fi echo ">>> sudo cp" $APP_PROP_FILE $VOLUMN_APP_PROP_DIR sudo cp $APP_PROP_FILE $VOLUMN_APP_PROP_DIR } # 设置 Volumn 根路径,值存放在 VOLUMN_ROOT_PATH 变量中。 VOLUMN_ROOT_PATH='/var/lib/docker/volumes' setDockerVolumnPath () { echo ">>> Docker Volumn 根路径:" ${VOLUMN_ROOT_PATH} read -p "是否修改Docker Volumn 根路径(输入1进入修改模式,否则按回车键)? " MODIFY_VOLUMN_PATH if [ "$MODIFY_VOLUMN_PATH" == "1" ] ;then read -p "请输入新的 Docker Volumn 根路径:" VOLUMN_PATH if [ ! -n "$VOLUMN_PATH" ] ;then echo "Docker Volumn 根路径输入有误,2秒后自动退出。" sleep 2 exit else echo ">>> 您输入的 Docker Volumn 根路径: $VOLUMN_PATH" fi fi } FAL_HOME=${VOLUMN_ROOT_PATH}'/falpolicy_falhome' setFalHome() { fallogs=${FAL_HOME}'/_data/fallogs' configFileInbox=${FAL_HOME}'/_data/configFileInbox' if [ ! -d ${configFileInbox} ];then echo 'mkdir -p '${fallogs} ${configFileInbox} mkdir -p ${fallogs} ${configFileInbox} chmod 777 -R ${FAL_HOME} fi } FALPOLICY_HOME_VOLUMN='falpolicy_falhome' VOLUMN_APP_PROP_DIR=${VOLUMN_ROOT_PATH}/${FALPOLICY_HOME_VOLUMN}/_data/falpolicy/config VOLUMN_APP_PROP_FILE=${VOLUMN_APP_PROP_DIR}/application.properties #VOLUMN_APP_PROP_FILE=${VOLUMN_ROOT_PATH}/falpolicy_solr_home/_data/application.properties POLICY_ACCESS_HOST_KEY='fal.policy.server.access.host=' if [ -f $VOLUMN_APP_PROP_FILE ];then getServerHostIP $VOLUMN_APP_PROP_FILE echo ">>> 当前 FalPolicy 服务器访问IP:" ${POLICY_ACCESS_HOST_VALUE} read -p "是否修改当前 FalPolicy 服务器访问IP(输入1进入修改模式,否则按回车键)? " MODIFY_HOST_IP if [ "$MODIFY_HOST_IP" == "1" ] ;then setServerHostIP fi else setServerHostIP fi setDockerVolumnPath setFalHome
4.2 方案2:docker service 跑起来后再修改 volumn 中的 application.properties 文件
#!/bin/bash f () { errcode=$? # save the exit code as the first thing done in the trap function echo "==================================================" echo "error $errorcode" echo "the command executing at the time of the error was" echo "$BASH_COMMAND" echo "on line ${BASH_LINENO[0]}" echo "==================================================" # do some error handling, cleanup, logging, notification # $BASH_COMMAND contains the command that was being executed at the time of the trap # ${BASH_LINENO[0]} contains the line number in the script of that command # exit the script or return to try again, etc. exit $errcode # or use some other value or do return instead } trap f ERR # 设置IP read -p "Please enter the serve host ip: " HOST_IP if [ ! -n "$HOST_IP" ] ;then echo "You have not input the serve host ip!" else echo "The ip you input is $HOST_IP." fi FILE_PATH='/var/lib/docker/volumes/falpolicy_falhome/_data/falpolicy/config/application.properties' POLICY_ACCESS_HOST_KEY='fal.policy.server.access.host=' POLICY_ACCESS_HOST_VALUE=`cat ${FILE_PATH} | grep ${POLICY_ACCESS_HOST_KEY} |awk '{print substr($1,31)}'` echo "Current falpolicy server access host is:" ${POLICY_ACCESS_HOST_VALUE} SOURCE_TEXT=fal.policy.server.access.host=${POLICY_ACCESS_HOST_VALUE} TARGET_TEXT=fal.policy.server.access.host=${HOST_IP} sed -i "s/${SOURCE_TEXT}/${TARGET_TEXT}/g" `grep ${SOURCE_TEXT} -rl ${FILE_PATH}` echo "IP change completed." echo '>>> docker service update --force falpolicy_falpolicy' docker service update --force falpolicy_falpolicy
这个文件可以单独调用,也可以在镜像部署脚本,如 startup.sh 中调用。脚本中涉及的 application.properties 文件在脚本同目录下。
5 获取volumn根目录(不限CentOS)
Fal_HOME=`docker volume inspect falpolicy_falhome --format "{{.Mountpoint}}"` # 输出:/var/lib/docker/volumes/falpolicy_falhome/_data echo ${FAL_HOME} VOLUMN_ROOT_PATH=${FAL_HOME%%volumes*}volumes # 输出:/var/lib/docker/volumes echo ${VOLUMN_ROOT_PATH}
6 挂载主机目录或主机文件
Docker 挂载主机目录的默认权限是 读写,用户也可以通过增加 readonly 指定为 只读。
docker run --mount type=bind,source=/src/webapp,target=/opt/webapp,readonly nginx docker run --mount type=bind,source=/src/webapp/index.html,target=/opt/webapp/index.html nginx
7 尽量保持容器存储层不发生写操作
容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中。
为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。
8 Volumn数据共享
8.1 compose 中共享
如果要授权一个容器访问另一个容器的Volume,在 compose 下很简单,创建一个 volumn 就共享了。例如下面的 volumn fastdfs-storage-path
,fastdfs-storage 服务负责往这个volumn里生产数据,nginx负责从这个 volumn里读数据,nginx映射的 /fastdfs 目录,在nginx docker中是可以直接访问这个路径的:
8.2 使用参数 -volumes-from 共享
我们可以使用 -volumes-from 参数来执行docker run,以共享 volumn。
$ docker run -it -h NEWCONTAINER --volumes-from container-test debian /bin/bash
root@NEWCONTAINER:/# ls /data
test-file
root@NEWCONTAINER:/#
9 备份、恢复或者迁移数据卷
数据卷还可以用来备份、恢复或迁移数据。为此我们使用--volumes-from
参数来创建一个挂载数据卷的容器,像这样:
$ sudo docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
这里我们启动了一个挂载dbdata卷的新容器,并且挂载了一个本地目录作为/backup卷。最后,我们通过使用tar命令将dbdata卷的内容备份到容器中的/backup目录下的backup.tar文件中。当命令完成或者容器停止,我们会留下我们的dbdata卷的备份。
然后,你可以在同一容器或在另外的容器中恢复此数据。创建一个新的容器
$ sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
然后在新的容器中的数据卷里un-tar此备份文件。
$ sudo docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
你可以对熟悉的目录应用此技术,来测试自动备份、迁移和恢复。
10 Compose Volumn 中的 external
volumes:
hostip:
external: true
表示使用外部 volumn,compose不再去创建它。