大凡先进技术的产生,都不是凭空捏造的,更不是花花瓶子作秀博眼球的。或是要解决某些需求,某些痛点。有其存在的道理和价值。
学习和使用一种技术,不是因为其高大上,好多大公司都在用就盲目去跟风,去学,去用。虽然开卷有益,多学习了解一点儿总是好的。但是,这样的效率不高,或者激不起学习的兴趣,或者太死板不能活学活用,学以致用。最好站在使用的角度去学习,实际操练一下,这是学习的一种方法。
上大学时学到傅里叶变换很枯燥。我站起来提问,问老师为啥要学习傅里叶变换?是为了考试通过吗?为了锻炼一下思维?能否讲讲它能用来做什么,实在不想死记硬背公式了,那样觉得就是为了应付考试。老师听了后,说同学你提的问题很好,很少有同学会问这个问题。然后就向我们讲了可以用在数字信号处理和图像处理等领域。同学们听过后都提高了不少兴趣,不再觉得枯燥了。
言归正传,关于docker,是这样解释的:
Docker 是一个开源的应用容器引擎,基于go语言 并遵从Apache2.0协议开源。
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。
如果只是看了这个解释,然后去按照某个教程捣鼓捣鼓,可能过一段时间又忘了。一是激不起太大兴趣,二是不能发挥它的实用价值。
我的需求是这样的,
我有三套ARM开发板,板子上的芯片虽然都是ARM,但是架构和指令版本都是不一样的。
我使用的虚拟机是Ubuntu14.04,我想在上面搭建嵌入式linux的交叉编译环境,以及go语言的开发环境和针对嵌入式的开发环境。
还需要把同样搭建好的环境指导提供给其他同事用。其他同事虽然也装了虚拟机,但是装的linux系统各式各样,有cenOS,有Ubuntu等,有32位也有64位的。有低版本也有高版本的。
我要装三个虚拟机吗?我要要求他们都装同样的系统吗?我要指导他们都捣鼓一套交叉编译环境吗?
我在一个虚拟机上装三套环境行不?或许可行的,但是环境之前有冲突,搞不好就掉坑里了。就比如环境变量来说,该如何配置才能做到相互不影响才好?
或者第三方厂商说你正在使用的系统版本太低了不支持。我要把原来的东西备份再更新下系统吗?
哦,想想都累,太折腾了。装三个虚拟机太占资源,还得来回切换,不好管理。要求他们换系统也不现实。每个人都指导配置一遍环境,效率太低了。
这时,Docker就派上大用途了。
有了它,我可以把环境搭建好直接给他们使用,不管他们装的是什么版本的linux系统,不影响他们现有的环境。他们也无需去配置交叉编译环境了。能保证我这是什么样,给他们的就是什么样。
docker run -t -i ubuntu:14.04 /bin/bash ,我就有了14.04的系统和环境。
docker run -t -i ubuntu:15.10 /bin/bash ,就相当于我有了15.10的系统和环境。
且切换速度很快,不占用太多空间。
回想之前,让一个对接的厂家提供给我们一套工具链使用。乖乖嘞,他说让我提供个大空间的U盘或者邮箱地址。说是他的工具链和配置好的环境都在虚拟机镜像里,要把好几G的镜像文件拷贝给我。结果我在网上下载了半天,效率那叫一个低啊。
如果他们提供我个docker容器,就简单了。
第一步,下载安装。
我的系统是ubuntu14.04,64位的。安装方式有几种,网上有很多教程。我选择了一种简单的方式,
直接:
sudo apt-get install -y docker-ce
注:Docker 要求 Ubuntu 系统的内核版本高于 3.10 ,查看本页面的前提条件来验证你的 Ubuntu 版本是否支持 Docker。
通过 uname -r 命令查看你当前的内核版本。
然后想验证下有没有验证成功,输入:docker version,
刚开始提示找不到docker命令,明明安装没报错怎么找不到呢?
于是做了个软链接:ln -sf /usr/bin/docker /usr/local/bin/docker
这样就算成功了吗?运行个demo试试:
docker run hello-world,
结果出现
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
原来docker的服务没能成功启动,查看下是不是,
service docker status
最后参照网上的办法,解决了。
docker run -it ubuntu bash
发现无论怎么做 都会出现这种问题!而且docker启动后立即停止stop了
看一下确实启动了 但是之后sudo service docker status查看下 发现还是stop/waiting
ok!搞事情!
查了一堆博文都没解决问题,但是发现一篇博文中有个关于docker的日志路径23333
解决之道:
1、root@myubuntu:/var/lib/docker#?tail -f /var/log/upstart/docker.log
INFO[0000] containerd successfully booted in 0.001790s? ?module=containerd time="2018-05-25T16:34:07.693705860+08:00" level=warning msg="failed to rename /var/lib/docker/tmp for background deletion: rename /var/lib/docker/tmp /var/lib/docker/tmp-old: file exists. Deleting synchronously" Error starting daemon: error initializing graphdriver: /var/lib/docker contains several valid graphdrivers: overlay2, aufs; Please cleanup or explicitly choose storage driver (-s <DRIVER>) ^C
反正就是说存储驱动有点多,需要清理下或者强行指定存储驱动!因为它有点蠢!
2、root@myubuntu:/var/lib/docker#?cd /var/lib/docker
3、root@myubuntu:/var/lib/docker#?ls
root@myubuntu:/var/lib/docker# ls
aufs? builder? containerd? containers? graph? image? init? linkgraph.db? network? overlay2? plugins? repositories-aufs? runtimes? swarm? tmp? tmp-old? trust? volumes
4、root@myubuntu:/var/lib/docker#?rm -rf aufs
这一步冲动了点? 应该先mv开 然后试一下 防止出问题
关于为啥删除aufs请看后面的内容
5、root@myubuntu:/var/lib/docker
#service docker start
6、root@myubuntu:/var/lib/docker
#?service docker status
OK!
auf和overlay2是两种存储驱动,auf适用于linux内核小于4的系统,overlay2适用于linux内核>=4的系统
接下来,
service docker start
通过交互模式启动容器(容器启动后,直接进入容器中,退出按ctrl+D)
运行Docker容器
现在可以看到在Bash Shell下建立Ubuntu容器是非常简单的,只需运行一行命令即可。
-i选项:让输入输出都在标准控制台进行
-t选项:分配一个tty
# docker run -i -t ubuntu /bin/bash root@696d5fd32bba:/#
故,在输出提示中,可以看到使用的标准Ubuntu容器。
现在可以在Ubuntu的Docker容器中使用Bash Shell。如果希望停止/断开连接,可以使用组合键Ctrl-p + Ctrl-q,然后就会返回到早先的窗口。
每次配置容器的参数不生效?需要从虚拟机往容器里拷文件怎么办?
挂载宿主机文件作为数据卷
docker run --name nginx-data3 -v /文件路径:/container路径 nginx
docker run -it --name imax283 -v /mnt/hgfs/b503/imax283:/imax283 ubuntu
--name 的含义为给容器起一个名字。
/mnt/hgfs/b503/imax283是我的本地文件存储的路径。
:/imax283是挂载在容器中显示的目录名。
后面的 ubuntu是指定的镜像。
查看有哪些镜像?可以用docker images
查看当前已存在哪些容器?
查看容器:
docker ps -a
想要进入对应容器的交互模式:
docker exec -it imax283 /bin/bash
这样就进入了名称为imax283的容器的交互模式
docker exec -it mygoenv /bin/bash
使用run命令创建容器
$ sudo docker run -dit [镜像:版本] [命令]
!-d: 表示后台运行
-i:允许你对容器内的标准输入 (STDIN) 进行交互。
-t:在新容器内指定一个伪终端或终端。
tar -cvf 123.tar include/
导入,导出容器
导出某个容器,非常简单,使用docker export命令,语法:docker export $container_id > 容器快照名
导入某个容器--docker import命令
有了容器快照之后,我们可以在想要的时候随时导入。导入快照使用docker import命令。
例如我们可以使用cat centos.tar | docker import - my/centos:v888 导入容器快照作为镜像
镜像保存/载入:docker load/docker save;将一个镜像导出为文件,再使用docker load命令将文件导入为一个镜像,会保存该镜像的的所有历史记录。比docker export命令导出的文件大,很好理解,因为会保存镜像的所有历史记录。
容器导入/导出:docker import/docker export;将一个容器导出为文件,再使用docker import命令将容器导入成为一个新的镜像,但是相比docker save命令,容器文件会丢失所有元数据和历史记录,仅保存容器当时的状态,相当于虚拟机快照。
删除容器
可以使用"docker rm 容器id"来删除一个终止状态的容器;若要删除一个运行中的容器,需要加-f参数。
最后,docker的强大功能远不止这些。这里只是从我自身使用的角度,用到了冰山一角。
比如安装其他资源如安装mysql,直接:
docker search mysql
拉取官方的镜像,标签为5.6
runoob@runoob:~/mysql$ docker pull mysql:5.6
等待下载完成后,我们就可以在本地镜像列表里查到REPOSITORY为mysql,标签为5.6的镜像。
runoob@runoob:~/mysql$ docker images |grep mysql mysql 5.6 2c0964ec182a 3 weeks ago 329 MB
通过 Dockerfile构建
创建Dockerfile
首先,创建目录mysql,用于存放后面的相关东西。
runoob@runoob:~$ mkdir -p ~/mysql/data ~/mysql/logs ~/mysql/conf
data目录将映射为mysql容器配置的数据文件存放路径
logs目录将映射为mysql容器的日志目录
conf目录里的配置文件将映射为mysql容器的配置文件
进入创建的mysql目录,创建Dockerfile
Dockerfile
什么是dockerfile?
Dockerfile是一个包含用于组合映像的命令的文本文档。可以使用在命令行中调用任何命令。 Docker通过读取Dockerfile中的指令自动生成映像。
docker build命令用于从Dockerfile构建映像。可以在docker build命令中使用-f标志指向文件系统中任何位置的Dockerfile。
例:
docker build -f /path/to/a/Dockerfile
Dockerfile的基本结构
Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令,’#’ 为 Dockerfile 中的注释。
[root@docker docker_demo]# cat Dockerfile # base image FROM centos # MAINTAINER MAINTAINER json_hc@163.com # put nginx-1.12.2.tar.gz into /usr/local/src and unpack nginx ADD nginx-1.12.2.tar.gz /usr/local/src # running required command RUN yum install -y gcc gcc-c++ glibc make autoconf openssl openssl-devel RUN yum install -y libxslt-devel -y gd gd-devel GeoIP GeoIP-devel pcre pcre-devel RUN useradd -M -s /sbin/nologin nginx # change dir to /usr/local/src/nginx-1.12.2 WORKDIR /usr/local/src/nginx-1.12.2 # execute command to compile nginx RUN ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-file-aio --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module --with-http_image_filter_module --with-http_geoip_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module && make && make install ENV PATH /usr/local/nginx/sbin:$PATH EXPOSE 80 ENTRYPOINT ["nginx"] CMD ["-g","daemon on;"]
镜像导出和载入
导出
docker [image] save [option]
option参数:
-o 表示导出到哪个路径
例子:
// 导出centos 7 的镜像 docker save -o centos_7.tar centos:7
载入
docker [image] load [option]
option参数:
-i 导入的文件
例子:
docker load -i centos_7.tar
注意:导入的镜像及其相关的元数据信息(包括标签)
容器导入和导出
导出容器
docker [container] export [-o | --output[=""]] CONTABER
例子:
// 导出一个容器 docker export -o centos_for_run.tar centos
导入容器
docker import [-c | --change[ =[] ] ] [-m | --message[=MESSAGE]] file | URL | -[REPOSITORY[:TAG]]
参数:
-c, --change=[] 可以对导入的同时执行对容器进行修改的Dockerfile指令
例子:
docker import centos_for_run.tar - centos:7
注意:
docker load 和 docker import 命令很相似,load 命令用来导入镜像存储文件到本地镜像库,import命令用来导入一个容器的快照到本地镜像库。
两者的区别:容器快照文件将丢弃所有的历史记录和元数据信息(只保留了容器当时的快照状态),而镜像文件存储文件将保存完整记录