购买了《Docker技术入门与实战》一书,再次充当一下速录人员,
将读书时的一些重要内容进行摘要记载下来,同时少量补充一些自己的思路。
同时,给自己留了一个课后作业,用来进行实战。
【课后作业内容】:自定义一个Docker容器,用来执行简单的java程序。
【课后作业目的】:前一个项目中的定时任务目前还是单点的,考虑将其搞成分布式定时任务。
■什么是Docker
网上介绍比较多,这里只总结几个关键点:
- 基于Go语言实现的云开元项目。
- Docker主要目标:一次封装、到处运行
- 用户操作Docker容器就像操作一个轻量级的虚拟机那样简单
- 开发者需要一种创建分布式应用程序的方式
- Docker容器是在操作系统层面上实现虚拟化,直接服用本地主机的操作系统,因此更加轻量级。
■Docker的核心概念
理解了下面三个Docker的核心概念,就能顺利地理解Docker的整个生命周期。
- 镜像(Image)
- 容器(Container)
- 仓库(Repository)
1)Docker镜像
Docker镜像(Image)类似于虚拟机镜像,可以将它理解为一个面向Docker引擎的只读模板,包含了文件系统。
例如:一个镜像可以只包含一个完成的Ubuntu操作系统环境,可以称为一个Ubuntu镜像。
镜像是创建Docker容器的基础。通过版本管理和增量的文件系统,Docker提供了一套十分简单的机制来创建和更新现有的镜像。
用户甚至可以从网上下载一个已经做好的应用镜像,并通过简单的命令就可以直接使用。
2)Docker容器
Docker容器(Container)类似于一个轻量级的沙箱,Docker利用容器来运行和隔离应用。
容器是从镜像创建的应用运行实例(ps:感觉像java的类与对象),
可以将其启动、开始、停止、删除,这些容器都是互相隔离、互不可见的。
可以把容器看做一个简易版的Linux系统环境(这包括root用户权限、进程空间、用户空间和网络空间等),
以及运行在其中的应用程序打包而成的应用盒子。
镜像自身是只读的。
容器从镜像启动的时候,Docker会在镜像的最上层创建一个可写层,镜像本身将保持不变。
PS:消防沙箱
3)Docker仓库
Docker仓库(Repository)类似于代码仓库,是Docker集中存放镜像文件的场所。
有时候会看到有资料将Docker仓库和注册服务器(Registry)混为一谈,并不严格区分。
实际上,注册服务器是存放仓库的地方,其上旺旺存放着多个仓库。
每个仓库集中存放某一类镜像,往往包括多个镜像文件,通过不同的标签(tag)来进行区分。
根据所存储的镜像公开分享与否,Docker仓库可分为公开仓库(Public)和私有仓库(Private)两种形式。
目前最大的共有仓库是Docker Hub,存放着数量庞大的镜像供用户下载。
国内公开的仓库包括Docker Pool等,可以提供文档的国内访问。
如果用户不希望公开分享自己的镜像文件,Docker也支持用户在本地网络内创建一个只能自己访问的私有仓库。
当用户创建了自己的镜像之后,可以使用push命令将它上传到指定的共有或私有仓库。
这样用户下次再另外一台机器上使用该镜像时,只需将其从仓库上pull下来就可以了。
可以看出,Docker利用仓库管理镜像的设计理念与Git非常类似。
■Docker安装
Docker官网上提供了安装命令,可以拿来即用。
操作途中遇到问题的时候,可以通过网上查找问题及解决方法。
1)在搜索引擎(百度等)搜索Docker官网。或者直接进入官网:https://docs.docker.com/
2)官网中点击Docs连接,进入相关的帮助文档界面。学会通过官网提供的文档了解某项技术。
3)选择在Linux上安装Docker。
4)选择Linux操作系统。我这里使用的是RedHad。
5)按照官网提供的命令安装就可以。
任何一门相对程序新技术,在对外发布的新版本时候,都会提供相应的使用手册。
通过官网网站提供的使用手册是学习一门新技术的一个重要手段。
具体命令如下:
①、确认Linux系统内核版本是否在3.10以上
命令:uname -r
②、更新yum
命令:sudo yum update
③、增加yum repo
命令如下:
$ sudo tee /etc/yum.repos.d/docker.repo <<-'EOF' [dockerrepo] name=Docker Repository baseurl=https://yum.dockerproject.org/repo/main/centos/7/ enabled=1 gpgcheck=1 gpgkey=https://yum.dockerproject.org/gpg EOF
执行结果如下:
④、安装Docker包
命令:sudo yum install docker-engine
⑤、设置Docker服务有效
命令:sudo systemctl enable docker.service
⑥、启动Docker
命令:sudo systemctl start docker
⑦、尝试拉取hello-world镜像
命令:sudo docker pull hello-world
⑧、查看镜像仓库
命令:sudo docker images
■安装遇到的问题
1)执行sudo docker run --rm hello-world这句命令的时候,提示下面错误信息。
原因:Linux系统防火墙未关闭。
解决办法:将防火墙由firewall改为iptables,然后关闭iptables,并禁止开机启动。
然后使用sudo docker pull hello-world尝试重新获取镜像之后,成功获取。
也可以使用sudo docker images来查看本地主机上已有镜像信息。
■Docker命令汇总(持续更新)
1)镜像(Docker运行容器前需要本地存在对应的镜像,镜像是创建Docker容器的基础。)
sudo docker pull ubuntu #从Docker Hub的Ubuntu仓库下载一个最新的Ubuntu操作系统镜像
sudo docker images #列出本地主机上已有的镜像
sudo docker search [TEAM] #搜索远端仓库中共享的镜像,支持的参数包括:
--automated=false 仅显示自动创建的镜像
--no-trunc-false 输出信息不截断显示
-s, --stars-0 指定仅显示评价为指定星级以上的镜像
sudo docker rmi [IMAGE] #删除镜像。其中IMAGE可以为标签或ID
sudo docker rmi -f [IMAGE] #强行删除镜像。(不推荐使用)
sudo docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] #基于已有镜像的容器创建新镜像。主要选项包括:
-a, --author="" 作者信息
-m, --message="" 提交信息
-p, --pause=true 提交时暂停容器运行
sudo docker save -o ubuntu_14.04.tar ubuntu:14.04 #存出本地的ubuntu:14.04镜像为文件ubuntu_14.04.tar
sudo docker load --input ubuntu_14.04.tar #从存出的本地文件ubuntu_14:04.tar导入镜像到本地镜像仓库。
sudo docker push NAME[:TAG] #上传镜像至仓库。默认上传到DockerHub官方仓库。
2)容器(容器是镜像的一个运行实例,所不同的是,它带有额外的可写文件层)
sudo docker run hello-world #启动Hello-world容器。
sudo docker run -t -i ubuntu_14:04 /bin/bash #启动一个允许用户交互的容器。
-t 选项让Docker分配一个伪终端
-i 选项让容器的标准输入保持打开
sudo docker run -d ubuntu_14:04 #以守护状态(后台)运行容器。
sudo docker run --rm ubuntu_14:04 #如果添加--rm标记,则容器在终止后会立即删除。注意--rm和-的参数不能同时使用。
sudo docker ps #查看容器信息。
sudo docker ps -a -q #查看处于终止状态的容器的ID信息。
sudo docker logs ID #获取指定容器(需要指定容器ID)的输出信息。
sudo docker stop ID #终止一个运行中的容器。另外,当Docker容器中指定的应用终止时,容器也自动终止。
sudo docker start ID #重新启动处于终止状态的容器。
sudo docker restart ID #将一个运行状态的容器终止,然后再重新启动。
sudo docker attach ID #进入容器进行操作。attach命令有时不方便。当多个窗口同事attack到同一个容器的时候,所有窗口都会同步显示。
sudo docker rm [OPTIONS] CONTAINER [CONTAINER...] #删除处于终止状态的容器。(可以使用docker ps命令来查看运行中的容器)
-f, --force=false 强行终止并删除一个运行中的容器
-l, --link=false 删除容器的连接,但保留容器
-v, --volumes=false 删除容器挂载的数据卷
sudo docker export ID >xxxx.tar #导出一个已经创建的容器到快照文件。(不管此时容器是否处于运行状态均可以导出)
cat xxxx.tar | sudo docker import - test/ubuntu:v1.0 #导入快照文件成为镜像。
实际上,既可以使用docker load命令来导入镜像存储文件到本地的镜像库,又可以使用docker import命令来导入一个容器快照到本地镜像库。
这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。
此外,从容器快照文件导入时可以重新制定标签等元数据信息。
3)仓库(Repository 是集中存放镜像的地方)
①、登录
可以通过执行sudo docker login命令来输入用户名,密码和邮箱来完成注册和登录。
可以先倒DockerHub的网站上(https://hub.docker.com/)注册信息。然后在登录。
②、基本操作
使用sudo docker search命令来查找官方仓库中的镜像。并利用sudo docker pull命令来将它下载到本地。
镜像资源可以分为两类:
一种是类似centos这类的镜像,成为基础镜像或根镜像。这些镜像由Docker公司创建,这样的镜像往往使用单个单词作为名字。
还有一种类型,比如tianon/centos镜像,是由DockerHub的用户tianon创建并维护的,带有用户名称为前缀,表名是某用户的镜像。
另外,在查找的时候可以使用-s N参数指定仅显示评价为N星以上的镜像,如下所示:
用户也可以使用docker push命令来将本地镜像推送到Docker Hub。
③、创建私有仓库
可以通过官方提供的registry镜像来简单搭建一套本地私有仓库环境。
sudo docker run -d -p 5000:5000 registry #这将自动下载并启动一个registry容器,创建本地的私有仓库服务。
默认情况下,会将仓库创造在容器的/tmp/registry目录下。可以通过-v参数来将镜像文件存放在本地的指定路径上。
例如下面的例子将上传的镜像放到/opt/data/registry目录:
sudo docker run -d -p 5000:5000 -v /opt/data/registry:/tmp/registry registry
此时,在本地将启动一个私有仓库服务,监听端口为5000。可以通过docker images来查看仓库镜像是否创建成功。
这里暂时给自己留一个作业:制作一个可以单独运行Java小程序的私有镜像仓库。
具体方法在后续的博客中会有更新。
■数据管理
用户在使用Docker的过程中,往往需要能查看容器内应用产生的数据,或者需要把容器内的数据进行备份,
甚至多个容器之间进行数据的共享,这必然涉及容器的数据管理操作。容器中管理数据主要有两种方式:
- 数据卷(Data Volumes)
- 数据卷容器(Data Volume Containers)
1)数据卷
数据卷是一个可供容器使用的特殊目录,它绕过文件系统,可以提供很多有用的特性:
- 数据卷可以在容器之间共享和重用
- 对数据卷的修改会立马生效
- 对数据卷的更新不会影响镜像
- 卷会一直存在,直到没有容器使用
数据卷的使用,类似于Linux下对目录或文件进行mount操作。
(ps:对于挂载的概念可以参考一篇博客http://blog.csdn.net/gongweijiao/article/details/8425629)
①、在容器内创建一个数据卷
在用docker run命令的时候,使用-v标记可以在容器内创建一个数据卷。多次使用-v标记可以创建多个数据卷。
下面使用training/webapp镜像创建一个Web容器,并创建一个数据卷挂载到容器的/webapp目录:
sudo docker run -d -P --name web -v /webapp training/webapp python app.py
-d 守护态运行
-P 允许外部访问容器需要暴露的端口。Docker会随记映射一个49000~49900的端口至容器内部开放的网络端口
--name 为容器自定义明明
-v 这里是在容器内创建一个数据卷
②、挂载一个主机目录作为数据卷
使用-v标记也可以指定挂载一个本地的已有目录到容器中去作为数据卷:
sudo docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py
上面的命令加载主机的/src/webapp目录到容器的/opt/webapp目录。
这个功能在进行测试的时候十分方便,比如用户可以放置一些程序或数据到本地目录中,然后在容器内运行和使用。
另外,本地目录的路径必须是绝对路径,如果目录不存在,Docker会自动创建。
Docker挂载数据卷默认的权限是读写(rw),用户也可以通过:ro指定为只读。
加了:ro之后,容器内挂载的数据卷的数据就无法修改了。命令为:
sudo docker run -d -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py
③、挂载一个本地主机文件作为数据卷
使用-v标记也可以从住家挂载单个文件到容器中作为数据卷:
sudo docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash
--rm 容器在终止后会立即删除
-it 启用交互模式
注意:如果直接挂载一个文件到容器,使用文本编辑工具对文件进行编辑的时候,可能会造成文件inode的改变,
(inode:储存文件元信息的区域,参考博客:http://www.ruanyifeng.com/blog/2011/12/inode.html)
会导致报错误信息,所以推荐的方式是直接关在文件所在的目录。
2)数据卷容器
如果用户需要在容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。
数据卷容器其实就是一个普通的容器,专门用它提供数据卷供其他容器挂载。使用方法如下:
首先,创建一个数据卷容器dbdata,并在其中创建一个数据卷挂载到/dbdata:
sudo docker run -it -v /dbdata --name dbdata ubuntu
然后,可以在其他容器中使用--volumes-from来挂载dbdata容器中的数据卷,
例如,创建db1和db2两个容器,并从dbdata容器挂载数据卷:
sudo docker run -it --volumes-from dbdata --name db1 ubuntu
sudo docker run -it --volumes-from dbdata --name db2 ubuntu
结果,就是db1和db2都挂载同一个数据卷到相同的/dbdata目录。
三个容器任何一方在该目录下的写入,在其他容器都可以看到。
注意:使用--volumes-from参数所挂载数据卷的容器自身并不需要保持在运行状态。
删除挂载容器时,需要补充几点:
•如果删除了挂载的容器(包括dbdata、db1、db2),数据卷并不会被自动深处。
•如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时显示使用docker rm -v命令来指定同时删除关联的容器。
■网络基础配置
大量的应用服务包括多个服务组件,这旺旺需要多个容器之间通过网络通讯进行相互配合。
Docker目前提供了【映射容器端口到宿主主机】和【容器互联机制】来为容器提供网络服务。
1)端口映射实现访问容器
在启动容器的时候,如果不指定对应参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的。
当容器中运行一些网络应用,要让外部访问这些应用时,可以通过-P(大写)或-p(小写)参数来指定端口映射。
当使用-P(大写)标记时,Docker会随记映射一个49000~49900的端口至容器内部开放的网络端口:
sudo docker run -d -P training/webapp python app.py
可以使用docker ps命令查看本地主机的49xxx端口被映射到了容器的5000端口。
当使用-p(小写)标记时,则可以指定要映射的端口,并且在一个指定端口上可以绑定一个容器。
可以使用docker port来查看当前映射的端口设置,也可以查看到绑定的地址。
支持的格式有如下三种:
- hostPort:containerPort
例如将本地的5000端口映射到容器的5000端口,可执行如下命令:
sudo docker run -d -p 5000:5000 training/webapp python app.py
此时默认会绑定本地所有接口上的所有地址,多次使用-p(小写)标记可以绑定多个端口,例如:
sudo docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py
- ip:hostPort:containerPort
指定映射使用一个特定的地址,比如localhost地址127.0.0.1。
sudo docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py
- ip::containerPort
绑定localhost的任意端口到容器的5000端口,本地主机会自动分配一个端口
sudo docker run -d -p 127.0.0.1::5000 training/webapp python app.py
2)容器互联实现荣期间通信
容器的连接(linking)系统是除了端口映射外另一种可以与容器中应用进行交互的方式。
它会在源和接受容器之间创建一个隧道,接受容器可以看到源容器指定的信息。
①、自定义容器命名
连接系统通过容器的名称来执行。因此,首先需要使用--name标记自定义一个好记的容器命名。
sudo docker run -d -P --name web training/webapp python app.py
命名完成后可以使用docker ps来验证设定的命名,也可以使用docker inspect来查看容器的名字。
注意:容器名称是唯一的。
②、容器互联
使用--link参数可以让容器之间安全的进行交互。
--link的格式为:--link name:alias,其中name是要连接的容器的名称,alias是这个连接的别名
下面创建一个新的数据库容器:
sudo docker run -d --name db training/postgres
删除之前创建的web容器:
sodu docker rm -f web
然后创建一个新的web容器,并将它连接到db容器:
sudo docker run -d -P --name web --link db:db training/webapp python app.py
这样一来,Docker在两个互联的容器之间创建了一个安全隧道,而且不用映射他们的端口到素质主机上。
在启动db容器的时候并没有使用-p或-P标记,从而避免了暴露数据库端口到外部网络上的风险。
当然,Docker也可以通过一些方式来为容器公开连接信息。这里不进行描述,后续实践时继续更新。
■使用DockerFile创建镜像
Dockerfile是一种文本格式的配置文件,用户可以使用Dockerfile快速创建自定义镜像。
(后续更新)
------------------------
网上找了一个图片,觉得比较形象,贴出来辅助理解。
--END--