Docker 学习笔记
刚好最近要用到docker,就翻开笔记找了下。觉得两年前写的用来复习足够了。
概念
Docker
Docker是基于Go语言实现的云开源项目,诞生于2013年初,最初发起者是dotCloud公司。
Docker的主要目标是“Build,Ship and Run Any App,Anywhere”,即通过对应用组件的封装、分发、部署、运行等生命周期的管理,达到应用组件级别的“一次封装,到处运行”。
Docker为应用的开发和部署提供了“一站式”的解决方案。
Docker的优势
- 更快速的交互与部署
- 更高效的资源利用
- 更轻松的迁移和扩展
- 更简单的更新管理
镜像
镜像(Image)就是一堆只读层(read-only layer)的统一视角,也许这个定义有些难以理解,下面的这张图能够帮助读者理解镜像的定义。
从左边我们看到了多个只读层,它们重叠在一起。除了最下面一层,其它层都会有一个指针指向下一层。这些层是Docker内部的实现细节,并且能够在宿主机的文件系统上访问到。统一文件系统(union file system)技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统。 我们可以在图片的右边看到这个视角的形式。
解释下,玩过PS的应该都知道图层的概念。一个图片由不同的图层叠加混合,最终形成一张完美的照片。其中底层可能原始图片,然后盖上一层黄色,再覆盖掉不想要的部分,或者添加点点缀,通过这种图层的方式,可以方便的合并出想要的图片。
容器
容器的定义
容器(container)的定义和镜像(image)几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。
细心的读者可能会发现,容器的定义并没有提及容器是否在运行。
要点:容器 = 镜像 + 可读层。
并且容器的定义并没有提及是否要运行容器。
运行态容器的定义
一个运行态容器(running container)被定义为一个可读写的统一文件系统加上隔离的进程空间和包含其中的进程。下面这张图片展示了一个运行中的容器。
正是文件系统隔离技术使得Docker成为了一个前途无量的技术。一个容器中的进程可能会对文件进行修改、删除、创建,这些改变都将作用于可读写层(read-write layer)。
下面这张图展示了这个行为。
我们可以通过运行以下命令来验证我们上面所说的:
docker run ubuntu touch happiness.txt
即便是这个ubuntu容器不再运行,我们依旧能够在主机的文件系统上找到这个新文件。
find / -name happiness.txt
/var/lib/docker/aufs/diff/860a7b...889/happiness.txt
容器和镜像的关系
镜像和容器的关系就像是java里面类和实例的关系一样。
也就是说,就像类可以产出多个不同的实例一样,镜像也可以产出多个不同的容器。并且实例是基于这个类,容器也是基于这个镜像的。
Centos7部署Docker
环境准备
- 安装必须的软件包
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
- 设置稳定版本库
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
- (自选)启用docker edge和test的版本库,默认是禁用。
sudo yum-config-manager --enable docker-ce-edge
sudo yum-config-manager --enable docker-ce-test
安装docker-ce
- 更新yum包索引
sudo yum makecache fast
- 安装Docker-CE最新版
sudo yum install docker-ce -y
- (自选)如果是生产环境,你可能需要安装特定版本,查询版本。
sudo yum list docker-ce.x86_64 --showduplicates | sort -r
- (自选)安装特定版本的docker-ce
sudo yum install docker-ce-
- 启动Docker
sudo systemctl start docker
- 验证是否正确安装Docker
sudo docker run hello-world
如果报错如下,请安装加速器:
[root@dockerserver ~]# docker run hello-world
Unable to find image 'hello-world:latest' locally
docker: Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers).
See 'docker run --help'.
安装加速器
我用的是DaoCloud的加速器,该网站同时维护了镜像。
运行脚本将--registry-mirror 加入到你的 Docker 配置文件 /etc/docker/daemon.json 中。 curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://9e94e867.m.daocloud.io
创建docker组并添加你的用户
一般情况,docker组不需要添加,安装docker的时候,系统自行添加了。
将用户添加到docker组 sudo usermod -aG docker $USER
或者新增一个用户到docker组,并指定密码。 sudo useradd $USER -g docker -p $PWD
私有仓库部署
在已部署dokcer的情况下,安装私有仓库。 docker run -d -p 5000:5000 --restart=always --name=registry --mount source=registry-data,target=/var/lib/registry registry:2
测试私有仓库
- 复制一份镜像
docker pull nginx
- 标记已存在的镜像
docker tag nginx $HOST_NAME:5000/nginx
- 将镜像推送到私有仓库
docker push $HOST_NAME:5000/nginx
如报错如下信息:
The push refers to a repository [dockerserver:5000/mynginx]
Get https://dockerserver:5000/v2/: http: server gave HTTP response to HTTPS client
解决方法:
在”/etc/docker/“目录下,创建”daemon.json“文件。在文件中写入: {"insecure-registries":["$ip/$hostname:5000"]}
制作镜像
docker commit
docker commit $container_id/$container_name testcommit:v1
docker import与docker load
镜像的存出和载入
镜像的存出 docker save -o nginx.tar nginx
镜像的载入 docker load --input nginx.tar
容器的导出和导入
容器的导出 docker export nginx > test.tar
容器的导入cat test.tar | docker import - test/nginx:v2.0
docker export和save的区别
export:容器快照文件将丢弃所有的历史记录和元数据信息。
save:镜像存储文件将保存完整记录,体积也要大。
此外,从容器快照文件导入时可以重新指定标签等元数据信息。
Dockerfile
例子:制作一个以Centos7为基础镜像,加上功能SSH+supervisor+jdk+Tomcat的镜像。
1、 创建一个目录,用来制作Dokcerfile
这里我用的是docker用户,自行创建的用户。 mkdir tomcat
目录为/home/docker/tomcat
2、 自行将tomcat和jdk的安装包放入第一步创建的目录下。
3、 制作supervisord.conf vi supervisord.conf
写入以下内容
# 配置文件包含目录和进程
# 第一段 supervsord 配置软件本身,使用 nodaemon 参数来运行。
# 第二段 supervsordctl 工具
# 第三段包含要控制的 2 个服务。每一段包含一个服务的目录和启动这个服务的命令
# (docker最新版overlay文件系统不支持socket,修改到/dev目录下)
[unix_http_server]
file=/dev/supervisor.sock
[supervisord]
nodaemon=true
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///dev/supervisor.sock
[inet_http_server]
port=*:9001
[program:sshd]
command=/usr/sbin/sshd -D
[program:tomcat]
command=/usr/local/tools/tomcat8_8080/bin/catalina.sh run
4、制作Dokcerfile vi Dokcerfile
写入以下内容
# 设置继承自哪个镜像
FROM centos
# 下面是一些创建者的基本信息
MAINTAINER linjk(2017-08-10)
# 修改时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 安装一些必备软件
RUN yum makecache fast \
&& yum install -y wget \
curl \
openssh-server \
net-tools
# tomcat jdk安装
ADD apache-tomcat-8.5.4.tar.gz /usr/local/src/
ADD jdk-8u121-linux-x64.tar.gz /usr/local/src/
ENV JAVA_HOME=/usr/local/src/jdk1.8.0_121 \
PATH=$PATH:$JAVA_HOME/bin \
CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
RUN mkdir -p /usr/local/tools \
&& cp -r /usr/local/src/apache-tomcat-8.5.4 /usr/local/tools/tomcat8_8080 \
&& rm -f /usr/local/src/apache-tomcat-8.5.4.tar.gz \
&& rm -f /usr/local/src/jdk-8u121-linux-x64.tar.gz
# 安装supervisor工具
RUN yum -y install python-setuptools \
&& easy_install supervisor \
&& mkdir -p /etc/supervisor
COPY supervisord.conf /etc/supervisor/
#容器需要开放SSH 22端口 tomcat 8080端口 9001端口为supervisord的web端口
EXPOSE 22 8080 9001
# 执行supervisord来同时执行多个命令,使用 supervisord 的可执行路径启动服务
CMD supervisord -c /etc/supervisor/supervisord.conf
5、制作镜像 docker build -t mytomcat .
6、基于此镜像执行容器 docker run --name=mytomcat -d -p 1025:22 -p 8081:8080 -p 9001:9001 mytomcat
数据卷
docker volume
注意旧版本可能不提供。
概念
数据卷是经过特殊设计的目录,可以绕过联合文件系统(AUFS),为一个或多个容器提供访问。
设计目的在于数据的持久化,它完全独立于容器的生命周期。
特点:
- 数据卷可以在容器中共享和重用
- 可以对数据卷里的内容直接进行修改
- 数据卷的变化不会影响镜像的更新
- 卷会一直存在,即使挂载数据卷的容器已经被删除
使用
docker run -it --name centos1 -v testV:/data centos bash
目前新版本建议使用--mount,以下命令等同于上一条命令 docker run -it --name=centos1 --mount source=testV,destination=/data centos bash
也可以在Dockerfile中,使用VOLUMN [data]
此时挂载的目录是docker随机的一个目录,可以用docker inspect $containID/$name来查看
数据卷容器
命名的容器挂载数据卷,其他容器通过挂载这个容器实现数据共享,挂载数据卷的容器,就叫做数据卷容器。
docker run -it --name centos2 --volumes-from centos1 centos bash
数据卷的备份与还原
备份 docker run --volumes-from centos1 -v /home/docker/volumeBackup:/backup --name centos3 centos tar -cvf /backup/test.tar /data
还原 docker run --name centos4 --volumes-from centos1 -v /home/docker/volumeBackup:/backup centos tar -xvf /backup/test.tar
网络
linux上的网络相关工具与变量。
- iptables:Iptables是与Linux内核集成的包过滤防火墙系统,几乎所有的linux发行版本都会包含Iptables的功能。
- ip-forward:linux的一个变量,默认为true,可以用命令
sysctl net.ipv4.conf.all.forwarding
查看
bridge模式
docker默认的网络模式,默认创建一个docker0的虚拟网卡,用来连接宿主机与容器,或者连接不同的容器。
网络的初始化动作:
- 创建docker0网桥
- 为docker0网桥新建子网以及路由
- 创建相应的iptalbes规则
自定义bridge
- 配置新的bridge
sudo yum install bridge-utils -y
sudo brctl addbr bridge0
sudo ip addr add 192.168.5.1/24 dev bridge0
sudo ip link set dev bridge0 up - 确认新的bridge信息
ip addr show bridge0
- 让docker启用新的bridge
修改/etc/docker/daemon.json {"bridge": "bridge0"}
- 重启docker,让配置生效
systemctl restart docker
- 确认iptables的信息
sudo iptables -t nat -L -n
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 192.168.5.0/24 0.0.0.0/0
其实还可以不用修改daemon,直接用network=bridge0
例如:
`docker run --network=bridge0 -itd --name=container3 busybox
`
拒绝容器间互连
默认情况下,docker是允许所有默认创建的容器网络互连的。要更改这个情况,需要修改--icc=false
修改/etc/docker/daemon.json,并重启docker让配置生效。 {"icc":false}
创建两个容器,这个时候两个容器的ip是没有办法ping通的。
容器的跨主机访问
使用网桥实现跨主机容器连接
不建议在生产环境中使用
优点
- 配置简单,不依赖第三方软件
缺点
- 与主机在同网段,需要小心划分IP地址
- 需要有网段控制权,在生产环境中不易实现
- 不容易管理
使用Open VSwith实现跨主机容器连接
Open VSwith是一个高质量的、多层虚拟交换机。目的是让大规模网络自动化,可以通过编程扩展,同时支持标准的管理接口和协议(例如:NetFlow,sFlow,SPAN,RSPAN,CLIL,LACP,802.lag)
使用weave实现跨主机容器连接
在 weave 1.2 版本之后,考虑到原先 sleeve 模式的网络性能较差,增加了 fastdp 的模式,该模式成为了 weave 启动时的默认模式
weave语义是编织的意思。目的是建立一个虚拟的网络,用于将运行在不同主机的Docker容器连接起来。
环境准备:
两台host,可以互相ssh操作,已经安装好docker,最好关闭防火墙,如实在不能关闭防火墙,则一定开通6783端口,此次测试直接关闭防火墙。
1、 安装weave(在两台host上一样的操作)
yum install wget -y
sudo wget -O /usr/local/bin/weave https://raw.githubusercontent.com/zettio/weave/master/weave
chmod a+x /usr/local/bin/weave
2、 启动weave路由器
host1上 weave launch
host2上 weave launch $host1_hostname/$host1_ip
备注:如果是三台host,weave launch任意一台就可以了。
3、 验证是否成功
确认weave网桥,需要提前安装bridge-utils,yum install bridge-utils -y
[root@docker1 test]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.024221da8762 no vethe46dc8d
weave 8000.3ac007c41fc5 no vethwe-bridge
确认weave容器已经运行
[root@docker1 test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
961093111b24 weaveworks/weave:latest "/home/weave/weave..." 2 minutes ago Up 2 minutes weave
4、 在两台宿主机上,分别开启一个容器,来验证是否可以ping通。
host1上 docker run -d -P --name=ljk-d1 docker1:5000/ljktest
weave attach 10.10.50.1/24 ljk-d1
host2上 docker run -d -P --name=ljk-d2 docker1:5000/ljktest
weave attach 10.10.50.2/24 ljk-d2
进入ljk-d1容器,测试是否可以ping通 docker exec -it ljk-d2 bash
ping 10.10.50.1
事实证明通过weave可以很简单的实现跨主机容器连接。
overlay模式自带实现跨主机容器的连接
环境准备:
三台虚拟机,安装好docker环境。
1、 初始化集群模式,并将当前节点作为管理节点 docker swarm init
输出信息如下:
Swarm initialized: current node (b6ff9xds5dnt90976zgds60cu) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-0x9prniau5i7tdygu0sk0ex1re713vannmq8dse698qniumace-0oz0kjq2945ylqdkez1j8n28i 192.168.0.137:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
2、 在另外两台节点上,执行上面提示语句,增加worker节点 docker swarm join --token SWMTKN-1-0x9prniau5i7tdygu0sk0ex1re713vannmq8dse698qniumace-0oz0kjq2945ylqdkez1j8n28i 192.168.0.137:2377
3、 查看集群状况 docker node ls
[root@docker3 ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
b6ff9xds5dnt90976zgds60cu * docker3 Ready Active Leader
mq1uwf54ry25o4dbv72iczpp9 docker5 Ready Active
w1eg1r2ttuygg06meo0zlntgi docker4 Ready Active
4、 创建overlay网络 docker network create --driver overlay --subnet 10.0.9.0/24 my-net
5、 创建service,用nginx来做测试 docker service create --replicas 3 --network my-net --name my-web nginx
6、 执行后,查看下service
结果虽然是3个实例,但是发现docker4和dockerr5上面的实例都失败了。
去网上看下谁踩了坑,发现是linux内核与overlay驱动的问题。
overlay驱动需要linux内核 >= 3.16
7、 升级下内核试试吧,可以参照centos内核升级,升级后内核版本是4.12,默认用的最新版。
重新测试,可以看到达到我们预期的结果了。
host模式
--net="host"创建出来的容器可以看到host上的所有网络设备。
容器中,对这些设备有全部的访问权限,因此docker提示我们,这种方式是不安全的。
但如果是在隔离良好的环境中使用这种方式,则问题不大。
container模式
--net="container:$name/$id"创建出来的网络与指定的container容器网络完全相同。
none模式
--net="none"创建出来的容器完全没有网络。
安全
Docker的安全性主要体现在:
- Docker容器的安全性:这是指容器是否会危害到host或其他容器
- 镜像的安全性:用户如何确保下载下来的镜像是可信的,未被篡改过的
- Docker daemon的安全性:如何确保发送给daemon的命令是由可信用户发起的
这里面容器的安全性是最大的问题,也是备受关注的问题
Docker容器的安全性
它的根源在于,容器和host共用内核,因此受到攻击面特别大,没有人能信心满满地说不可能由容器入侵到host。
共用内核导致的另一个严重问题是,如果某个容器里的应用导致linux内核崩溃,那么整个系统都会崩溃。
安全策略
- Cgroup
- ulimit
- 容器组网
- 容器+虚拟化
- 文件系统级防护
- SELinux
附录
版本简介
Docker从17.03开始分为社区版与企业版,版本控制方案转向基于时间的YY.MM形式。
社区版并非阉割版,只是改了个名字。
企业版则提供了一些收费的高级特性。
Docker CE(社区版)
Docker CE是免费提供的,是开发人员和小团队希望开始使用Docker构建容器应用程序的理想选择。
它为开发人员提供每月或每季度的发布节奏。
特征
- 最新版本的Docker容器引擎针对可用的基础架构进行了优化
- 获得频繁发布版本节奏
- 无限公众和免费作为服务
- 自动构建为服务
- 图像安全扫描服务
支持
- 每月版本的前沿功能
- 季度稳定发布,四个月的维护窗口
- Docker社区论坛上的社区支持和当前版本的错误修复
Docker EE(企业版)
Docker EE是为企业开发人员和IT团队建立和管理规模生产中的关键应用程序的软件,支持和认证订阅。
Docker EE是一个面向IT的容器即服务平台,用于管理和保护内部和云中不同基础设施的不同应用。
特征
- 认证基础设施(企业操作系统和云提供商)上最新版本的Docker容器引擎
- 来自第三方ISV供应商的认证容器
- 来自网络和存储供应商的认证插件
- Docker数据中心,用于集成的集装箱管理和安全
- 直观易用的Web用户界面
- 通过精细的基于角色的访问控制(RBAC),基于节点的RBAC和LDAP / AD集成来实现安全的多租户
- 具有密码管理,图像签名和图像扫描的端到端安全性
- 图像管理与私人注册,存储和缓存
- 基于政策的自动化与图像宣传
支持
- 可预测的季度发布节奏,每次发布一年的维护
- 企业级支持具有定义的SLA和私有支持渠道
- 所有受支持版本的后端修补程序和修补程序
- 第三方认证插件和容器的协作支持和保证
其他版本
docker 1.9特性
- 跨主机网络:新的网络设备可以支持用户创建基于多个主机的虚拟网络,使容器间可以跨网络通信。
- 持久化存储:Docker 1.9 包含一个重新设计的完整存储卷管理系统,这使得用户可以更加容易的从前端来管理这些数据卷。
- Docker Swarm 1.0:修复bug并对其进行大量优化。Docker公司在1000个节点上测试了30000个容器,swarm可以如丝般润滑的运行。
- Docker Engine 1.9:新的Docker Engine中加入了如下新特性:Dockerfile 的构建时参数、并行镜像 pull、自定义 stop 信号、AWS CloudWatch logging driver和磁盘 I/O metrics。
- Docker Compose 1.5:Docker Compose 是一个定义并运行多容器应用的工具,它有如下更新:支持 Windows、Compose 文件中的环境变量、对多环境更好的支持、和 networking 集成和Compose file 校验。
- Docker Toolbox:这个工具可以使Mac和Windows支持这些新特性。
- Docker Registry 2.2:主要做了以下更新:支持 Google Cloud Storage、只读模式、支持可配置主机名、基于文件的存在配置、可配置的 HTTP 健康检查和可配置的 HTTP 响应 headers。详细的更新说明可以参照《Docker 1.9 发布:Swarm 和跨主机网络进入 production-ready 阶段》和Announcing Docker 1.9: Production-ready Swarm and Multi-host Networking。
docker 1.10版本
- 新增.dockeringore功能,开发人员可以在 Dockerfile之后添加.dockerignore文件
- 提交过程暂停容器,docker commit --pause=false
- 跟踪日志,docker logs --tail 10
- 允许使用tar文件作为docker build的上下文
- 在一个容器中绑定挂载整个文件系统
docker 1.11版本
- 可以直接在runC和containerd上构建引擎
- Networking 在新版本中得到了改善
- swarm不再是实验版了,更新为swarm1.2
docker 1.12版本
- 内置docker swarm:集群管理,子命令有init, join, leave, update
- docker service:服务创建,子命令有create, inspect, update, remove, tasks
- docker node:节点管理,子命令有accept, promote, demote, inspect, update, tasks, ls, rm
- docker stack/deploy:试验特性,用于多应用部署, 类似与 docker-compose 中的特性。
docker 1.13版本
基于本次更新主要以功能增强和bug修正为主,所以对之前版本的影响不是很大。
比如弃用的仅仅为docker daemon命令弃用或者docker pull的repo:shortid语法弃用这样影响较小的部分。
另外plugin功能的正式发布会带来一点影响。如果你在docker1.12中使用了plugin相关的试验性功能,你需要先行删除你的那些plugin以及/var/lib/docker/plugins/下的json文件,等docker版本更新之后再重新安装。
试验性的功能还是有一些变化的风险性的。
资源链接
官方网站
- Docker 官方主页
- Docker 官方博客
- Docker 官方文档
- Docker Hub
- Docker 的源代码仓库
- supervisord 官方网站
- Dockerfile参考
- Dockerfile最佳实践
其他参考
- daocloud 国内仓库
- supervisord 基础
- docker安全工具
- weave github
- weave 部署与测试
- 跨主机容器访问简介
- docker web ui