Docker入门教程

以下所有笔记来源于B站狂神老师(我为狂神老师举大旗!!!)

1.docker概述

(1)出现

一款产品:开发→上线,开发人员一套环境,想要用需要重新配置环境

开发和运维运行不了部分原因:版本更新、环境不一

需要逐台配置环境,时间成本资源成本消耗巨大

如果发布项目时使用jar包打包程序,但是下载后需要重新配置环境

传统方案:开发人员发布jar包,运维人员配置环境

现在方案:开发人员打包部署上线,不需要运维人员

Docker就是包括环境一起打包,这样使用的时候就不需要单独重新配置

举个栗子,如果本地安装了Python3的版本,但是程序需要Python2的版本,docker打包的时候把Python2打包起来,下在本地和Python3互不影响,这是docker的核心思想——互相隔离。

(2)docker历史

2010年,几个搞IT的年轻人成立了一家公司dotCloud

他们做一些云计算服务,虚拟机有关的容器技术

他们将自己的容器化技术命名为docker

诞生之初并没有引起行业注意

2013年,Docker开源(开放源代码)

虚拟机:在windows中装一个vmware,通过软件可以虚拟出一台或者多台电脑,缺点是笨重

虚拟机是虚拟化技术,Docker容器技术也是属于虚拟化技术

vm:linux原生镜像(就是一个电脑),如果需要开多个镜像,就需要做隔离,每个隔离都是一台电脑,很笨重

docker:同样需要做隔离,镜像机制只部署了最核心的环境(可以自己添加部分,如jdk),非常的小巧

docker是基于go语言开发的开源项目

docker hub:https://hub.docker.com/

docker官网:Docker: Accelerated Container Application Development

docker文档地址:https://docs.docker.com/

(3)docker和虚拟技术不同

虚拟机技术缺点:模拟一个电脑资源占用多,冗余步骤多,启动慢,笨重

容器化技术不是模拟完整的操作系统

传统虚拟机:虚拟出一个完整的硬件,运行一个完整的操作系统,然后在系统上安装和运行软件

容器内的应用直接运行在宿主机内核中,容器没有自己的内核,并没有虚拟硬件,非常轻便

每个容器都是相互隔离的,每个容器中都有自己的文件系统,互不影响

devops(开发、运维)使用docker

应用更快速的交付和部署:

传统:一堆帮助文档,安装程序

docker:打包镜像发布测试,一键运行

更便捷的升级和扩容:

使用docker像搭积木一样

项目打包成一个镜像,扩展服务器ABC等等

更简单的系统运维:

容器化之后,开发和测试高度一致

更高效的计算机资源利用:

docker是内核级别的虚拟化,可以在一个物理机上运行很多个容器实例,服务器的性能可以被压缩到极致

2.docker安装

(1)基本组成

上图实现一个过程,通过客户端启动容器,容器需要下载

镜像(image):

docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,tomcat镜像==>run(镜像需要运行)==>tomcat容器(提供服务器)。通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中)

容器(container):

docker利用容器技术,独立运行一个或者一个组应用,通过镜像来创建的

启动,停止,删除(基本命令)

就好比一个简易的linux系统

仓库(repository):

仓库就是存放镜像的地方

仓库分为共有仓库和私有仓库

(2)安装docker

uname -r
cat /etc/os-release

查看系统信息,我的环境如上

第一步:卸载旧环境

 sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

这里因为我没有安装docker才会这样子

第二步:下载需要的工具包

sudo yum install -y yum-utils

这里我安过了

sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

第三步:设置镜像仓库

sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

https://download.docker.com/linux/centos/docker-ce.repo 国外的源很慢

http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 阿里云的源

更新一下 

yum makecache fast

第四步:安装docker docker-ce社区 docker-ee企业版

yum install docker-ce docker-ce-cli containerd.io

第五步:测试

systemctl start docker
docker version

尝试运行hello world(经典的hello world)

docker run hello-world

查看镜像列表

docker images

第六步:卸载

yum remove decker-ce docker-ce-cli contained.io
rm -rf /var/lib/docker

卸载依赖,删除资源

阿里云服务器镜像加速:

找到镜像加速器,也可以直接搜

找到自己对应的系统,在自己的服务器上键入他的代码即可配置完成

3.docker使用

(1)docker run运行流程

上图是docker run的运行流程

docker是一个Client-Server结构的系统(客户端/服务器),docker的守护进程运行在主机上,通过socket从客户端访问

docker server会接受到client的指令,就会执行命令

(2)docker的常用命令

帮助命令

docker version
显示版本信息

docker info
显示docker的系统信息,包括镜像和容器的信息

docker 命令 --help
查看相关命令的帮助信息

镜像命令:

docker images
查看本地主机上的镜像

docker images -aq
-a 显示所有
-q 仅显示ID

docker search 镜像名:镜像版本
搜索镜像
--filter=STARS=1 设置收藏数的筛选条件

docker pull 镜像名:版本号
下载镜像

这里docker pull mysql 等价于docker pull docker.io/library/mysql:latest(版本号不可以乱写,必须是他有的版本)

当尝试下载mysql 5.7版本的时候,我们可以看见docker的分层下载有一部分显示已经存在,这是因为我们刚刚下载最新版的时候已经下过的东西他不会再重复下,docker这样的处理方式优势体现在在大量的镜像可以共用,极大程度的节省了内存,这也是联合文件系统的核心思想

docker rmi 镜像名
删除镜像
-f 强制删除镜像

这里删掉了mysql5.7,但是一点儿也不影响mysql最新版的使用

删除全部镜像的方法,跟linux命令行中的用法一样,$(command)将command的输出作为一个字符串返回,这样docker rmi -f就会递归删除所有的镜像,删除多个镜像镜像id以空格隔开

容器命令:

前提:有了镜像才可以创建容器

先下载一个centos的容器

docker run [可选参数] image
创建容器并启动
--name="Name" 容器名字
-d 以后台方式运行
-it 使用交互式方式运行,进入容器查看内容
-p 指定容器端口(-p ip:宿主机端口:容器端口——容器端口映射到宿主机端口)
-P 随机指定端口

root名后面跟的是主机名,观察主机名可以发现我们已经进入centos容器了,exit退出容器

docker ps
查看运行的容器
-a 列出当前正在运行的容器+历史运行过的容器
-n=? 显示最近运行的?个容器
-q 只显示容器ID

使用exit退出容器,docker ps查看没有刚刚的centos容器,加上-a参数即可看到,因为我们使用exit退出容器后他停止了容器的

Ctrl+P+Q将容器挂载到后台并不会退出

docker stop 容器ID
停止容器

docker exec -it NAMES /bin/bash,docker exec用于在容器中执行命令,-it用于分配一个交互式终端并启动一个bash shell,此时我们在容器中使用exit退出容器时,容器内部的bash shell会终止,但容器本身不会停止, 我们可以使用docker stop停止容器

docker rm 容器id
删除容器
docker rm -f $(docker ps -aq)
删除所有容器
docker ps -a -q | xargs docker rm
删除所有容器(xargs是读入前面命令的输出传递给后面的命令)

不能直接删除正在运行的容器,除非rm -f强制删除,一般是先停止容器再删除

docker start 容器ID
启动容器
docker restart 容器ID
重新启动容器
docker stop 容器ID
停止当前正在运行的程序
docker kill 容器ID
强制停止当前容器

以上操作:docker run运行一个容器,然后在容器内使用exit退出容器,docker ps看不到因为exit退出的容器并不是正在运行的容器,然后docker ps -a可以查看所有运行的容器和历史容器,然后使用docker start运行容器,再次使用docker即可查看正在运行的程序,然后使用docker stop停止容器,再一次使用docker ps就看不到了(此例中docker stop处的用法同docker kill)

常用其他命令:

docker run -d 容器ID
后台启动容器

PS:可以看到我们使用docker run -d centos在后台启动一个程序后,我们使用docker ps无法查看到他处于运行状态,docker容器使用后台运行,就必须要有一个前台进程,docker发现没有的话,他就会自动停止

docker logs 容器ID
查看指定容器日志
-t 显示时间戳
-f 实时监控
--tail 控制行数

以上操作:docker run打开一个容器,然后Ctrl+P+Q将其挂到后台,docker ps能看到他正在运行的状态,使用docker logs查看日志,发现并没有任何输出(因为他什么都没干),然后我们使用docker run -d在后台启动一个容器,同时执行shell脚本(每隔一秒钟就输出一遍“hello_world”),再次使用docker logs查看日志,可以成功看到日志,因为-f参数实时监视,所以一直在刷新

同上例,我们启动一个容器并执行了一些命令,Ctrl+P+Q将其挂到后台,使用docker logs即可查看日志

docker top 容器ID
查看容器中进程信息

以上操作:使用docker top命令查看容器内部进程

docker inspect 容器ID
查看镜像源数据

以上操作:使用docker inspect查看容器的镜像源数据

docker exec -it 容器ID bashshell
在指定容器中新开一个shell
docker attach 容器ID
进入原来的shell

以上操作:使用docker ps查看当前正在运行的容器,使用docker exec -it以交互式方式进入容器,在容器内部使用uname -r查看容器内部信息

以上操作:我们使用docker attach进入容器正在执行的终端,不会启动新的终端,以为刚刚写的是一个死循环,所以这里并不能用Ctrl+C停止或者使用Ctrl+P+Q挂到后台去,这里我简单粗暴的直接杀掉了这个进程

docker cp 容器ID:容器路径 主机路径
从容器内拷贝文件到主机

以上操作:使用docker run启动一个容器,然后我们在tmp目录下创建一个文件,Ctrl+P+Q将挂到后台去(经过尝试如果使用exit退出容器是不影响拷贝的),然后使用docker ps获刚刚运行的容器的id,再使用docker cp将指定容器内/tmp目录下的test.txt拷贝到主机/tmp目录下的demo.txt,可以看到拷贝成功

4.docker练习

安装nginx

(1)搜索镜像

以上操作:使用docker search命令搜索镜像

(2)拉取镜像

以上操作:使用docker pull拉取镜像,然后使用docker images查看是否下载成功,这里可以看到我们成功下载镜像nginx

(3)启动镜像

我们使用docker run启动一个nginx镜像,并将其命名为nginx01,还将nginx01的80端口映射到本地主机的8080端口

然后访问一下我们的主机,很明显,我们可以成功访问~

安装tomcat

搜索镜像

以上操作:我们使用docker search搜索tomcat的版本

安装镜像

以上操作:使用docker pull下载tomcat最新版,然后使用docker images查看镜像,这里可以看到我们成功下载了tomcat的最新版

启动镜像

以上操作:我们使用docker run创建一个容器的实例,结合-d参数将其挂到后台,-p将tomcat01的8080端口挂到宿主机的8081端口。然后使用curl访问,返回的网络状态码居然是404。这并不意味着我们访问的不对或是部署有问题。我们使用docker exec交互式连接tomcat01,然后我们对其网站目录进行查看,发现什么都没有,所以访问的时候报错404也是正常的

发现问题

问题:缺少部分linux命令;webapps中没有东西。

因为:阿里云镜像的问题,默认下载的是最小的镜像,所有不必要的东西都会剔除掉,因为他要保证最小的可运行环境

解决:webapps是tomcat默认的web应用程序部署目录,webapps.dist这个目录包含了tomcat发行版默认提供的实例web程序,我们可以拷贝到webapps中

以上操作:将webapps.dist中的文件使用cp拷贝(-r递归拷贝)到webapps目录中,这样访问tomcat01时就看起来比较好看啦~

 以上操作:使用docker stats查看运行中容器的性能统计信息命令

5.docker镜像原理

(1)镜像是什么

镜像是一种轻量级,可独立执行的软件包,用来打包软件运行环境和基于运行环境开发的软件,他包含运行某个软件所需要的所有内容,包括代码、运行时、库、环境变量和配置文件。

这样的好处就是不需要运维人员再去部署环境,所有的应用,直接打包成docker镜像,就可以直接跑起来

得到镜像的方式:从远程仓库下载;朋友拷贝;自己制作一个dockerfile

(2)UnionFS联合文件系统

我们pull镜像的时候看到的就是这个东东

联合文件系统是一种分层轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。联合文件系统是docker镜像的基础,镜像可以通过分层来继承(上文提到的多个镜像可以共用文件)。

特性:一次同时加载多个文件系统,但从外面看起来只能看到一个文件系统,联合加载会把各层的文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录

(3)docker镜像加速原理

docker镜像实际上是由一层一层的文件系统组成的,这种层级的文件系统就是联合文件系统

bootfs包含了bootloader和linux内核。用户是不能对这层作任何修改的。在内核启动之后,bootfs实际上会卸载掉(系统启动需要引导加载)

rootfs则包含了一般系统上的常见目录结构,类似于/dev, /proc, /bin等等以及一些基本的文件和命令

对于一个精简的操作系统,他的rootfs可以很小,只需要一点点基本的命令就行了(ls、cd等等),底层直接用的host的内核

(4)分层理解

上文提到,在下载了mysql最新版之后,又下载了mysql5.7版,可以看到他是一个一个下的,这就是分层的概念,也看到有些文件显示已经下载过了,这就意味这mysql5.7和mysql最新版共用同一个文件,这就是联合文件系统。

所有的docker镜像都起源于一个基础镜像层,进行修改或者增加新内容时,就会在当前镜像层之上创建新的镜像层

上图表示的意思是,基于Ubuntu创建一个新的镜像,每次增加新的内容就创建一个镜像层,添加额外层的同时,镜像使用保持的当前所有镜像的组合。

上图的意思,每个镜像层包含了三个文件,第一个镜像层中的文件123也是一个镜像层,就是第一个镜像层是由三个小镜像层组成的。一共就相当于六个小镜像层

上图表示了一个概念,在外部看来只有六个文件,因为文件7是文件5的pro版本,这种情况下上层镜像层中的文件覆盖了底层镜像层,就相当于文件的更新版变成了新的镜像层添加到镜像中去。docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统

上图展示了最终展示的所有镜像合并对外提供统一的视图

特点:

docker镜像层都是可读的,当容器启动时,一个新的可写层被加载到镜像的顶部

这一层就是容器层,容器层以下都是镜像层

上图表示了一个概念,我们run一个镜像得到一个容器实例,所有的操作都是基于容器层的

(5)commit镜像

问题:docker pull下来的的tomcat中,其webapps文件夹是空的,我们每次都要把webapps.dist拷贝进webapps,非常的麻烦

解决:在第一次完成拷贝操作后将其提交成为一个新的副本

docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG版本]
提交容器成为一个新的副本

以上操作:使用docker run开启一个容器实例,-d参数将其挂到后台,docker ps查看到他为运行的容器,docker exec重新进入容器,执行拷贝操作,并退出镜像

以上操作:使用docker commit操作提交了一个新的镜像,-m参数添加描述为new tomcat,作者为ybtdj,新的镜像名为tomcat_pro,版本为1.0,然后使用docker images查看所有镜像时我们可以看到一个新的镜像——tomcat_pro,他的大小为464m,原来没有webapps的tomcat只有460m

6.容器数据卷

(1)什么是容器数据卷?

docker的理念就是将应用和环境打包成一个镜像。如果数据都存在让其中,那么我们删除容器数据就会丢失(相当于删库跑路),所以我们需求数据持久化,需要mysql数据可以存储在本地。容器之间可以有一个数据共享的技术。docker容器中产生的数据,同步到本地,这就是卷技术,目录的挂载,将容器的目录挂载到宿主机上

总结:为了容器的持久化和同步操作,容器间可以数据共享

(2)数据卷

方法一:

docker run -it -v 宿主机目录:容器内目录 
目录映射,可以映射多个,跟端口映射异曲同工(-p 宿主机端口:容器端口)

以上操作:使用docker run创建一个容器实例,以-v参数将容器的/home目录挂载到宿主机的/home/test目录并交互式打开它,然后再在容器内的/home目录下创建一个内容为“hello_world”的test.txt文件,并退出容器,查看当前文件夹即/home/test下的txt文件,成功看见我们想看见的东西。使用docker ps -a -q | xargs docker rm 删掉所有的容器,使用docker ps -a查看所有运行以及运行过的容器发现并没有容器,再次查看当前文件夹下的txt文件,在容器已经删除的情况下我们还是看到了那句“hello_world”(双向绑定)

安装mysql实现数据持久化

以上操作:使用docker search mysql搜索数据库版本

以上操作:使用docker pull下mysql5.7,然后使用docker images查看所有镜像,可以看到mysql5.7赫然在列

 以上操作:使用docker run启动一个mysql5.7的容器实例,其中-d意为在后台启动,-p将容器的3306端口映射到宿主机的3366端口,-v挂载了两个目录,将/etc/mysql/conf.d目录(mysql配置文件)挂载到了/home/mysql/conf,/var/lib/mysql目录(mysql数据库服务器默认数据目录)挂载到了/home/mysql/data(-v参数可以挂载多个目录),-e环境配置了mysql的密码为root,命容器名为mysql01

以上操作:使用netstat -tunpl查看当前系统中所有处于监听状态的tcp和udp连接(3366是mysql5.7映射的端口,3306是我本地mysql的端口),键入mysql -u=登录用户名 -p=密码 --port=端口号,他会提醒我们在命令行输入密码是不安全的行为,但是还是成功连接到映射端口3366的mysql(使用其他的主机试过了也是可以成功进行登录的)

以上操作,我们分别查看了/home/mysql目录下conf和data两个目录的文件,证明我们成功挂载

以上操作:使用docker ps查看正在运行的mysql5.7的容器id,然后使用docker inspect查看其源数据,看到了mounts挂载了两个目录

以上操作:先在宿主机查看data文件夹,然后连接远程数据库,创建新的数据库,再次回到宿主机内查看data文件夹,结果表明成功挂载实现双向绑定(反之亦然,在宿主机删除test数据库相关文件,在mysql远程连接上查看所有数据库也没有test数据库)

docker volume ls
查看所有卷的情况

以上操作:使用docker run创建了一个名为tomcat01的容器实例,-d参数在后台启动,-v匿名挂载,挂载的/usr/local/tomcat目录。然后查看了docker volume命令的用法,其中,create子命令用于创建卷,inspect子命令用于显示一个或多个卷的详细信息,ls子命令用于列出所有的卷,prune子命令用于删除未使用的本地卷,rm子命令用于删除一个或多个卷,然后我们使用docker volume ls查看所有的卷,可以看到volume name为一串随机的名字,这就是匿名挂载

以上操作:使用docker volume ls查看所有的卷,然后使用docker volume inspect查看第一个卷的详细信息,我们可以看到Mountpoint(挂载点)变量中写了目录,上文提及的挂载是以-v 宿主机目录:容器目录的方式将容器目录挂载到宿主机目录,这里我们并没有指定宿主机目录,他就会随机生成一个目录进行挂载

以上操作:我们使用docker run运行tomcat01容器实例,-d将其挂到后台,-v挂载容器内/home目录,以往我们挂载时宿主机目录写的是绝对路径也就是从/开始写的,-v /home:/home的意思是将容器内home目录挂载到宿主机目录的/home,这里的意思是挂载名为home,然后使用docker volume ls查看所有卷,我们可以成功看到有个挂载名为home的挂载目录,然后使用docker volume inspect home可以看到Mountpoint的值为一个指定的目录,所有docker容器内的卷,没有指定目录的情况下都是在/var/lib/docker/volumes/xxx/_data,我们通过具名挂载可以很方便的找到卷

总结:-v 容器内路径是匿名挂载,-v 挂载名:容器内路径是具名挂载,-v 宿主机绝对路径(以/开头):容器内路径为指定路径挂载

-v 容器内路径:ro rw改变读写权限,ro为read only,rw为read write可读可写

一旦设定了权限,容器对挂载目录有限制了,默认为rw可读可写,如果有ro,容器内部是无法改变目录的,只有宿主机可以改变

(3)初识dockerfile

dockerfile就是用来构建docker镜像的构建文件,就是命令脚本,通过这个脚本可以生成镜像,镜像是一层一层的,脚本就是一条条的命令,每个命令都是一层镜像,文件中的内容 大写的指令 参数

docker bulid -f dockerfile文件路径 -t 镜像名:版本号 .
创建镜像(最后有一个点号不要忘记了哦)

以上操作:查看当前路径为/home/dockerfile_test,创建一个文件,其内容为一些命令:FROM centos指定基础镜像为centos,VOLUME ["volume01","volume02"]用于生成两个卷volume01和volume02,通过dockerfile的 VOLUME 指令可以在镜像中创建挂载点,这样只要通过该镜像创建的容器都有了挂载点。但在dockerfile中无法指定宿主机上对应的目录,是自动生成的(使用docker inspect 容器名可以查看),CMD输出---OK---(应该是版本问题没有输出,网上有说法说CMD只执行一条命令),然后CMD /bin/bash指定启动容器时要执行的命令即打开一个交互式shell。然后我们使用docker build构建docker镜像,-f参数指定要使用的dockerfile的路径,-t参数指定镜像名和版本号,最后有个.别忘记了,表示在当前目录寻找构建上下文需要的文件。构建完成后我们使用docker images可以查看到我们的镜像ybtdj:1.0

以上操作:使用docker run创建一个名为ybtdj01的实例,然后我们查看他的根目录可以看到有volume01和volume02,我们Ctrl+P+Q将他挂到后台去,使用docker ps确认他是在运行中的状态,然后使用docker inspect查看他的源数据,查看Mounts这里,可以看到挂载情况为匿名挂载(VOLUME参数详解参考:https://zhuanlan.zhihu.com/p/376651701)

(4)数据卷容器

实现两个或多个容器间的数据共享

参数 --volumes-from 父容器

以上操作:使用docker run创建一个名为ybtdj02的容器,-it以交互式启动,--volumes-from设置其父容器为ybtdj01。进入ybtdj02后Ctrl+P+Q挂到后台,使用docker ps查看ybtdj01和ybtdj02均是启动状态,使用docker attach重新进入ybtdj01,此时我们去volume01目录下创建一个内容为hello_world的test.txt文件,退出ybtdj01,进入ybtdj02,去volume01目录下同样查看到了test.txt的内容hello_world^0^

以上操作:使用docker stop和docker rm -f删除ybtdj01,使用docker ps -a可以查看到我们已经成功删除掉了ybtdj01,使用docker start启动ybtdj02,并使用docker exec -it新开一个交互式shell,可以成功看到我们volume01目录下的test.txt,可以看到数据还在,由此可见,只要还有一个容器还在使用,数据就不会丢失

总结:容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止,一旦持久化到了本地,就是容器数据卷的概念,是挂载在宿主机上的, 这个时候彻底删除数据只有删掉宿主机里面的数据,而不关容器的事情

7.dockerfile

dockerfile是用来构建docker镜像的文件

(1)dockerfile介绍

构建步骤如下:

编写一个dockerfilewenjian

docker build构建成为一个镜像

docker run 运行镜像

docker push 发布镜像(dockerhub、阿里云镜像仓库)

上图以centos为例,去docker hub官网上查看centos的dockerfile,他跳转到了github,可以看到这个centos的dockerfile只是一些基础的东西,甚至没有ping这些常用的命令,每一条命令都是一层一层的,可以理解把所有命令组装起来成了我们的镜像层,同样,我们也可以制作我们自己的镜像(docker hub中99%的镜像都是从sratch过来的,然后配置需要的软件和配置来构建文件)

(2)dockerfile构建过程

每个保留关键字(指令)必须全部是大写

执行从上到下执行

# 表示注释

每一个指令都会创建一个新的镜像层并提交

dockerfile面向开发

dockerfile:构建文件,定义了一切的步骤,等价于源代码

dockerimages:通过dockerfile构建生成的镜像,最终发布和运行的东东

docker容器:容器就是镜像运行起来提供服务的东东

(3)dockerfile指令

FROM #基础镜像,一切从这里开始构架,centos ubuntu

MAINTAINER #镜像是谁写的,姓名+邮箱

RUN #docker镜像构建的时候需要运行的命令

ADD #添加内容

WORKDIR #当前工作目录

VOLUME #指定挂载目录位置

EXPOSE #指定对外端口

CMD #指定容器启动时要运行的命令,只有最后一个会生效,可以被替代

ENTRYPOINT #指定容器启动时要运行的命令,可以追加命令

ONBUILD #当构建一个被继承的dockerfile时候就会触发指令

COPY #类似ADD,将文件拷贝到镜像中

ENV #构建的时候设置环境变量

(4)构建一个我们自己的centos

以上操作:使用pwd查看当前路径,在当前路径下创建一个名为mycentos的文件,编辑其内容:FROM centos:centos7指定基础镜像为centos7,我尝试过指定基础镜像为centos也就是默认会自己下载最新版,但是他执行yum下载东西的时候会报错,根据https://blog.csdn.net/Ctrl_kun/article/details/123835198这篇文章中写的我尝试更改成centos7,就可以了;MAINTAINER ybtdj<1466718907@qq.com>设置了维护者的信息,也就是ybtdj和他的电子邮件地址;ENV MYPATH /usr/local设置了一个环境变量叫MYPATH,其值为/usr/local;WORKDIR $MYPATH设置了当前工作目录为$MYPATH也就是/usr/local;两条RUN命令安装了vim文本编辑器和net-tools工具集,-y参数使得他们自动安装;EXPOSE 80开放了容器的80端口;两个CMD命令是echo输出,最后一个CMD命令定义了容器启动后的命令,即/bin/bash开启一个shell

以上操作:使用docker buile构建容器为ybtdj1.0,使用docker images查看所有的镜像,我们构建的ybtdj1.0赫然在列。构建完成后使用docker run启动一个名为centos01的容器,其镜像为centos。可以看到在centos01中我们并没有vim和ifcongfig命令,当前工作目录也是根目录/。按下Ctrl+P+Q将其挂到后台,使用docker run启动一个名为ybtdj_centos01的容器,其镜像为我们自己构建的ybtdj_centos。可以看到在ybtdj_centos01中他可以执行vim命令和ifcong命令功能,当前的工作目录也是/usr/local

docker history 镜像名
列出本地镜像的变更记录

以上操作:用docker history分别查看centos和ybtdj1.0的变更记录,可以很直观的看见centos的制作,ybtdj的比centos多了几条过程,同理,我们也可以查看其他的镜像来看看他们是怎么做的

(5)CMD和ENTRYPOINT的区别

以上操作:编辑了一个dockerfilecmd文件,查看其内容:FROM centos基础镜像来自centos,CMD ["ls","-a"]表示执行ls -a命令。接下来使用docker build建立镜像为cmdtest,使用docker run运行镜像,可以看见他执行了ls -a命令

以上操作:我们使用docker run新建一个容器,加上参数-l是想执行追加一个命令参数执行命令ls -a -l,可是他报错了,因为-l替换掉了ls -a,单独一个-l是错误的命令,这种情况下我们要执行命令的话就使用docker run追加ls -a -l命令替换掉CMD指令的ls -a

以上操作:我们在当前文件夹下新建一个文件,查看其内容:FROM centos以centos为基础镜像,ENTRYPOINT ["ls","-a"]在容器启动时执行命令ls -a,然后我们使用docker build构建容器,使用docker run创建一个容器,他自己执行了ls -a命令,再一次使用docker run创建容器,这次我们加上了-l,很明显的看到这里他执行的命令是ls -a -l,由此可知ENTRYPOINT指令可以追加命令(这些细小的地方虽然实际使用并没有什么太大的用处,但是仔细研究起来实在是太有意思啦)

制作tomcat镜像

编写镜像文件tomcat的压缩包,jdk的压缩包

编写dockerfile文件,官方命名Dockerfile,build会自动寻找这个文件,不需要-f指定

以上操作:在当前目录下创建一个Dockerfile文件,其内容为:FROM centos7设置基础镜像为centos7,MAINTAINER ybtdj<1466718907@qq.com>设置作者的基本信息为ybtdj,其邮箱地址为14667158907@qq.com,COPY readme.txt /usr/local/readme.txt复制当前目录下的readme.txt文件到镜像中的/usr/local/readme.txt,ADD jdk-8u11-linux-x64.tar.gz将当前目录下jdk-8u11-linux-x64.tar.gz压缩文件解压缩到/usr/local下,同理也是解压apache-tomcat-9.0.83.tar.gz压缩文件到/usr/local下,RUN yum install vim -y在镜像中运行命令下载vim工具-y是自己确认的意思,ENV MYPATH /usr/local设置环境变量MYPATH的值为/usr/local,WORKDIR $MYPATH设置当前工作目录为$MYPATH即/usr/local,ENV JAVA_HOME /usr/local/jdk1.8.0_11设置环境变量JAVA_HOME为java jdk的安装路径,ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar设置环境变量$CLASSPATH为java类库路径($JAVA_HOME/lib/dt.jar包含了java AWT图形用户界面工具包,$JAVA_HOME/lib/tools.jar包含了java编译器和其他开发工具所需的类),ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.83设置环境变量CATALINA_HOME为apache tomcat的安装路劲,ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.83设置环境变量CATALINA_BASH为tomcat的安装路径,ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin将java jdk和apache tomcat的二级制目录文件添加到环境变量PATH中去,以便能直接运行java和tomcat命令,EXPOSE 8080暴露容器8080端口,CMD /usr/local/apache-tomcat-9.0.83bin/startup.sh & tail -f /usr/local/apache-tomcat-9.0.83/bin/logs/catalina.out在容器启动时运行tomcat的startup.sh脚本,并使用tail命令来实时查看tocmat的日志文件catalina.out的输出。使用docker build构建镜像,因为我们使用的文件名为Dockerfile是约定俗称的文件名,所以不需要-f指定,我们定义镜像名为mytomcat,别忘记.了哦

以上操作:使用docker run运行容器,-d在后台运行,--name指定名字为mytomcat01,-p指定容器8080端口映射到宿主机的9090端口,-v挂载目录,将容器上的/webapps/test目录挂载到宿主机的指定路径下的/test目录便于部署web应用,将容器上的/logs目录挂载到宿主机指定路径下的/tomcatlogs目录便于查看tomcat容器内的日志信息

以上内容:我们使用docker exec在mytomcat01容器内再开一个shell,进入容器后我们ls可以看到当前目录有我们在Dockerfile里面COPY进来的readme.txt文件,也可以看到当前目录是我们指定的/usr/local,退出容器后,我们使用curl请求宿主机9090端口同样可以看到请求成功,由此可知我们的服务部署的没有任何问题

以上操作:在容器的webapps目录映射的对应目录下,创建一个index.html文件,然后访问tomcat服务的/test,可以看见服务部署成功,由此可知我们可以在宿主机上部署服务而不用进入容器内部署服务(index.html的内容是我去csdn上ha的代码,昼夜变换形态的按钮,可能有些不规范,但是还是可以证明服务是部署成功了的)

以上操作:在容器logs目录映射的对应目录下,我们成功查看了tomat服务器的运行状态和配信息,验证了我们两个目录都挂载成功

8.发布镜像

(1)docker hub

https://hub.docker.com/注册自己的账号

在服务器上提交自己的镜像

docker login -u 用户名 -p 密码
dockerhub登录命令

登录完毕后就可以提交镜像

docker push #上传镜像到我们的服务器上

docker tag #添加标签

以上操作:使用docker login登录我们的docker hub账号,看到“Login Succeeded”即为登录成功,使用docker images查看所有镜像,然后使用docker push镜像名就可以上传镜像了,可以看到我们提交也是按照提交的层级进行提交的

(2)阿里云镜像

登录自己的阿里云

找到容器镜像服务

创建命名空间,一个账户只能有三个命名空间

创建容器镜像

浏览阿里云镜像信息

以上操作:我们使用docker login登录了我们的阿里云账户,docker images查看所有镜像,docker push上传指定的镜像

9.小结

以上为docker的运行流程

以上操作:docker save导出成tar文件,-o指定路径;docker load导入tar文件,-i指定输入路径,-q设置为静默模式即无过多冗余信息

这张图仔细看看,相信是看的懂的啦

10.Docker网络

(1)理解docker0

以上操作:清空本地的所有镜像和容器

以上操作:使用ip add查看网卡信息,第一个lo是本机回环地址,第二个etho是阿里云内网地址,第三个docker0是docker0地址

以上操作:使用docker run运行centos容器,因为我们已经清理了镜像所以他重新下载了centos,-it进入交互式界面,使用yum下载net-tools相关指令,使用ifconfig查看容器内网卡信息,可以看到第一个eth0是ip地址,第二个lo是本机回环地址

以上操作:我们在宿主机尝试ping容器centos01,可以看到我们在宿主机尝试ping我们的吧唧,是可以ping通的,linux可以ping通容器内部

原理:我们每安装一个docker容器,docker就会给docker容器分配一个ip,只要安装了docker就会有一个docker0网卡,是桥接模式,使用的技术是evth-pair技术

以上操作:当我们再次启动一个容器centos02,Ctrl+P+Q挂到后台,可以看到宿主机有两对儿网卡,evth-pair就是一对儿虚拟的设备接口,他们都是成对儿出现的,一端连着协议,一端彼此相连,因为有这个特性,evth-pair充当一个桥梁,连接各种虚拟网络设备(OpenStac,docker容器之间的连接,OVS的连接都是使用evth-pair技术)

以上操作:使用docker attach再次进入centos01,尝试ping容器centos02,可以看到成功ping通,得到结论容器和容器之间可以互相ping通

结论:centos01和centos02公用同一个路由器docker0,所有的容器不指定网络的情况下都是docker路由的,docker会给我们的容器分配一个默认的可用ip。docker中的所有网络接口都是虚拟的,虚拟的转发效率高(内网传递)。容器删除,对应的网桥就没有了。

(2)--link参数

以上操作:查看当前运行的容器,一个centos01一个centos02,我们使用docker exec在centos02上执行ping命令希望ping通centos01,发现ping不了一点儿。我们使用docker run基于centos7创建一个容器centos03,使用--link参数连接到centos02,使其可以访问centos02的服务,我们进入容器centos03,下载net-tools相关命令,Ctrl+P+Q将其挂到后台。使用docker ps确定当前运行了三个容器。使用docker exec在centos03上尝试直接ping容器centos02,可以ping通(但是这只是单向的,只能centos03容器ping容器centos02)

以上操作:使用docker exec查看centos03的/etc/hosts文件(主机名解析文件),我们惊喜的发现我们创建容器centos03的时候--link容器centos02就是把centos02写到了centos03的配置文件,增加了映射(同理我们编辑配置文件也可以实现以服务访问容器的操作),--link参数现已不建议使用

以上操作:查看docker network的帮助命令:connect将一个容器连接到指定的docker容器中,create创建新的docker网络,disconnect从指定的网络中断开连接,inspect用于查看指定网络的详细信息,ls列出所有已创建的docker网络, prune用于清理不再使用的docker网络,rm用于删除docker网络。我们使用ls子命令列出了所有的docker网络,然后列出指定网络的详细信息,可以看出来这就是我们的docker0

(3)自定义网络

网络模式:

bridge:桥接docker 0.2 → 0.1 ← 0.3(默认)

none:不配置网络

host:和宿主机共享网络

container:容器网络连通(用的少,局限很大)

以上操作:我们查看docker network create的帮助命令。docker network ls查看所有的网络,然后我们使用docker network create创建一个名为mynet的网络,--driver指定网络连接模式,--subnet指定网关和子网掩码,--getway指定网关。再次使用docker network ls查看所有网络,可以看到我们创建的mynet赫然在列(平时我们使用docker run创建容器的时候默认有一个参数--net bridge指定网络为桥接模式)

以上操作:使用docker run命令创建两个基于centos7的容器,centos-mynet01和centos-mynet02,其网络模式均为我们创建的mynet,当然,是交互式创建的,使用Ctrl+P+Q挂到后台。使用docker ps确认他们是在运行状态中。使用docker network inspect查看创建的网络mynet,可以清楚的看见有两个容器,正是我们的centos-mynet01和centos-mynet02。然后使用docker exec在centos-mynet01上ping四次centos-mynet02的ip,成功ping通,尝试直接pingcentos-mynet02的容器名也是可以的(自定义网络已经帮我们维护好了对应的关系,推荐我们平时这样使用网络)

好处:不同的集群使用不同的网络,保证集群是安全和健康的

docker0的网络内部无疑是通的,mynet网络内部无疑也是通的,如果要让centos01能ping通centos-mynet01和centos-mynet02,就让centos01连接到网络mynet

以上操作:使用docker ps查看当前运行的容器,查看docker network connect的帮助命令,使用docker network connect连接centos01到mynet网络,使用docker network inspect查看mynet网络的元数据的时候,我们惊喜的发现他所谓的连接到网络就是将centos01添加到mynet中去,此时centos01一个容器有两个ip(可以把centos01的docker0ip看成私网ip内网ip,把mynet的ip看成公网ip外网ip)

以上操作:使用docker exec在centos01上执行命令,分别ping容器centos-mynet01的ip和centos-mynet02的容器名,均可以ping通

使用docker inspect查看centos01的源数据,可以在NetworkSettings网络设置中可以看到两个网关两个ip

结论:跨网络操作别人,就要使用docker network connect连通

11.结语

Docker的学习之旅虽告一段落,但容器技术的奇妙世界却是辽阔无垠。在这小小的容器中,承载着巨大的可能。不论是开发、测试、部署,Docker都带来了许多的便捷。很幸运能学到一些知识,路漫漫其修远兮,吾将上下而求索。

新手上路,请多指教~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值