docker排雷记

上周末使用docker做了一个简化应用分发的小例子,但今天在最新版本的docker上一运行就出错,研究了好半天,终于将这些坑都填过去了,这里记录一下。

挂载目录用户权限问题

我是将dockerfiles相关文件放在windows系统上的,然后通过virtualbox虚拟机的共享文件夹功能将目录共享给Linux的,这样在Linux下就会看到这些文件的用户组是vboxsf, 这些文件的权限为770。

[jeremy@centos7-local dockerfiles]$ ls -l
总用量 1
-rwxrwx--- 1 root vboxsf 688 2月   3 11:53 docker-compose.yml
drwxrwx--- 1 root vboxsf   0 2月   2 09:51 initdb
drwxrwx--- 1 root vboxsf   0 2月   3 11:28 tools
drwxrwx--- 1 root vboxsf   0 2月   2 18:05 wars

这时使用-v将目录挂载到docker容器

1

docker run --name=test -v `pwd`/wars:/var/lib/jetty/webapps -p 8080:8080 -d jetty:9

这时目录挂载过去后权限就很不对了,如下

root@15ba64dfbe33:/var/lib/jetty# ls -l

total 0

drwxr-xr-x 3 jetty jetty 17 Feb 3 01:57 lib

drwxr-xr-x 2 jetty jetty 6 Jan 18 00:38 resources

drwxr-xr-x 2 jetty jetty 193 Feb 3 01:57 start.d

drwxrwx--- 1 root 984 0 Feb 2 10:05 webapps

可以看到webapps目录的用户组为984, 文件权限是770。而jetty是以jetty用户运行的,自然就无法读取webapps目录下的内容。

查了下,解决这个问题有四种办法:

  • 在宿主机上创建与容器中需要的用户及用户组,创建的用户及用户组的ID必须与容器中的一致。在运行docker run -v ...命令前,将要挂载的目录权限设置正确。
  • 将要挂载的目录设置为容器中存在的用户及用户组,比如设置为root用户,在宿主机与容器中都存在root用户与root用户组,而且root用户与root用户组的ID是一致的。
  • 修改容器中用户及用户组的ID,使宿主机上的用户及用户组ID在容器内可被识别,有网友写了一个脚本来完成这件事。
  • 运行docker run -v ...命令时,使用--user--group更改容器运行进程的用户及用户组。同样要求指定的用户在容器里是存在的,一般来说也就只能使用root了。

这几种方法都有缺点,还是很麻烦。也在关注是否有其它更好的办法。

depends_on失效了

docker-compose.yml里使用depends_on指定了web服务依赖于db服务,但web服务还没等db服务就绪就启动了,最终web服务启动失败。

查了下文件,发现官方文档有这么一句话:

Note: depends_on will not wait for db and redis to be “ready” before starting web - only until they have been started. If you need to wait for a service to be ready, see Controlling startup order for more on this problem and strategies for solving it.

最后参考这里, 使用wait-for-it方案解决了问题。

version: '2'
services:
  ssm-mysql:
    image:  'mysql'
    volumes:
      - ./initdb:/docker-entrypoint-initdb.d
    environment:
      - MYSQL_DATABASE=ssm-db
      - MYSQL_ROOT_PASSWORD=123456
  ssm-web:
    image: 'jetty:9'
    depends_on:
      - ssm-mysql
    links:
      - ssm-mysql
    volumes:
      - ./wars:/var/lib/jetty/webapps
      - ./tools:/tools
    entrypoint: ["/tools/wait-for-it.sh", "ssm-mysql:3306", "-s", "-t", "60", "--", "/docker-entrypoint.sh"]
    ports:
      - "8080:8080"
    environment:
      - MYSQL_PORT_3306_TCP_ADDR=ssm-mysql
      - MYSQL_PORT_3306_TCP_PORT=3306
      - MYSQL_ENV_MYSQL_DATABASE=ssm-db
      - MYSQL_ENV_MYSQL_ROOT_PASSWORD=123456

使用docker的-p选项不监听端口

直接使用docker的-p选项,发现docker宿主机并不监听指定的端口,在docker宿主机上可以访问该端口,但外部就无法访问该端口了。

[jeremy@centos7-local dockerfiles]$ docker run --name=test -p 8080:8080 -d jetty:9
dbb672d6c3bec87bd9048911798f7d3941e6681ebdd60e0bb54332b8a083ae3d
#宿主机并不监听8080端口
[jeremy@centos7-local dockerfiles]$ lsof -i :8080
# 但在docker宿主机上wget可访问8080,外部就无法访问8080了
[jeremy@centos7-local dockerfiles]$ wget http://127.0.0.1:8080
--2017-02-03 21:01:43--  http://127.0.0.1:8080/
正在连接 127.0.0.1:8080... 已连接。
# 发现原来是docker-proxy这个东东在工作
[jeremy@centos7-local dockerfiles]$ ps -ef|grep docker
...
root      3190  3050  0 20:58 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8080 -container-ip 172.17.0.2 -container-port 8080
...

查阅官方文档后,发现dockerd存在--userland-proxy这个选项。

–userland-proxy true Use userland proxy for loopback traffic

于是给dockerd加上--userland-proxy=false选项,然后问题解决了。这个选项应该是为安全性考虑的吧,默认只允许docker宿主机访问-p出来的端口,外部要想访问则需要配置相应的iptables规则。默认如果是这样也太不易用了。

参考

https://docs.docker.com/engine/installation/linux/centos/ https://docs.docker.com/engine/installation/linux/linux-postinstall/ https://docs.docker.com/engine/admin/systemd/ https://github.com/schmidigital/permission-fix https://docs.docker.com/compose/compose-file/ https://docs.docker.com/compose/startup-order/ https://github.com/vishnubob/wait-for-it https://docs.docker.com/engine/reference/commandline/dockerd/

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏写代码的海盗

Docker学习总结之Run命令介绍 Operator exclusive options

Docker学习总结之Run命令介绍 本文由Vikings(http://www.cnblogs.com/vikings-blog/) 原创,转载请标明.谢谢!...

33450
来自专栏熊二哥

SpringBoot详细研究-02数据访问

Springboot对数据访问部分提供了非常强大的集成,支持mysql,oracle等传统数据库的同时,也支持Redis,MongoDB等非关系型数据库,极大的...

31890
来自专栏程序小工

【Docker】--安装与配置

docker 是 linux 虚拟化技术,能够一键式搭建开发环境,并且能保证运维、开发、上线部署的环境完全一致,避免了运行环境差异性带来的问题。 具有简单、轻...

14430
来自专栏程序员同行者

redis集群搭建

14840
来自专栏bboysoul

使用docker-machine在vmware vsphere上创建docker虚拟机

这个其实没什么好说的,我就是为了记录一下创建的过程,如果不会使用docker-machine。

14820
来自专栏偏前端工程师的驿站

CentOS6.5菜鸟之旅:U盘安装CentOS64位

一、前言                                      之前下载了个CentOS7 32位版,一下就安装成功了,但由于其目录结构等与...

32550
来自专栏云计算教程系列

如何在Ubuntu 16.04上使用Docker Swarm安装和保护OpenFaaS

无服务器架构从开发人员隐藏服务器实例,并且通常公开允许开发人员在云中运行其应用程序的API。这种方法可以帮助开发人员快速部署应用程序,因为他们可以将配置和维护实...

48310
来自专栏恰童鞋骚年

Java微服务之Spring Boot on Docker

本文学习前提:Java, Spring Boot, Docker, Spring Cloud

29740
来自专栏容器云生态

overlayfs存储驱动的使用以及技术探究

overlayfs存储驱动的使用以及技术探究 1.overlayfs 基本概念 一种联合文件系统,设计简单,速度更快。overlayfs在linux主机上只有两...

415100
来自专栏Samego开发资源

IDEA配置Tomcat服务器并创建Java Web项目

31430

扫码关注云+社区

领取腾讯云代金券