阅读声明:
1.本文为个人学习笔记,内有多图,需要看图片中的控制台的代码,以便理解;
2.文中所出现的服务器ip地址与暴露端口均为无效地址。服务器实例已被注销,请 勿尝试连接或进行无效的攻击。维护网络秩序,你我有责;
3.文章中的图部分引用与网络,侵权请联系删除;
4.部分知识理解均为个人见解,若有不当之处,欢迎指出,共同交流学习。
一款产品必经之路 开发 -> 上线,dev 与 prod 是两个环境。配置端口、配置环境都不同,每一个机器都要部署环境,配置起来非常麻烦,还可能出错。
常常会出现这样一种情况:程序在我的电脑上可以运行,换了个地方就不行了。
环境版本更新,导致服务不可用
在服务器配置应用环境,不能跨平台(windows 开发 -> Linux 上线)
于是,我们希望,发布一个项目可以连带环境一起打包 jar ->(jar + (Redis MySQL jdk) 一起上线?
Docker 给以上的问题,提出了解决方案
Java — jar(环境)— 打包项目带上环境(镜像)— (Docker仓库)— 下载镜像即可运行
Docker与虚拟机技术的不同
DevOps(开发、运维)
应用更快速的交付和部署
传统:一堆帮助文件,安装程序
Docker:打包镜像发布测试,一键运行
更便捷的升级和扩缩容
使用Docker之后,部署应用就像搭积木
项目打包成一个镜像,拓展 服务器A 拓展服务器B
更简单的系统运维
在容器化之后,我们的开发,测试环境都是高度一致的,不存在说“我的电脑能运行的情况了”
更高效的计算机资源利用
Docker是内核级别的虚拟化,可以在一个物理机上运行很多个容器实例,服务器的性能可以被压榨到极致。
image: docker镜像就好比一个模板,可以通过这个模板来创建容器服务,tomcat镜像 -> run -> tomcat01容器(提供服务),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)。
container: Docker 利用容器技术,独立运行一个或者一个组应用,通过镜像来创建的
启动、停止、删除、基本命令
目前就可以把这个容器理解未就是一个建议的 linux 系统
repository: 仓库就是存放镜像的地方,仓库分为公有仓库和私有仓库
安装Docker
安装yum插件
yum install -y yum-utils
看到后面的Complete!
即表示插件安装成功
设置镜像的仓库为阿里云镜像仓库
yum-config-manager
–add-repo
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
更新yum软件包索引
yum makecache fast
安装docker镜像 docker-ce 社区 docker-ee 企业版 默认安装最新版
yum install docker-ce docker-ce-cli containerd.io
安装的过程中有两个地方需要输入y
等待片刻,最后出现Complete!即是安装完成
启动docker服务
systemctl start docker
这样即表示启动成功
如果你还不相信的话,你可以输入个
docker version
来查看安装的版本号
运行Hello world程序
docker run hello-world
查看下载的镜像
docker images
卸载docker
yum remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker
配置阿里云镜像加速
分别执行以下4个命令
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://jqwynzjh.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
在etc下创建docker目录
更换docker镜像
重新加载配置文件 重启docker
简单的Hello-World程序是怎么执行的?
底层原理
Docker 是怎么工作的?
Docker 是一个Client - Server 结构的系统,Docker的守护进程运行在主机上,通过Socker从客户端访问,DockerServer 接收到 Docker - Client 的指令,就会执行这个命令。
Docker 为什么比VM快?
Docker有着比虚拟机更少的抽象层,由于Docker不需要Hypervisor实现硬件资源虚拟化,运行在Docker容器上的程序直接使用的都是实际物理机的硬件资源,因此在Cpu、内存利用率上Docker将会在效率上有明显优势。
Docker利用的是宿主机的内核,而不需要Guest OS,因此,当新建一个容器时,Docker不需要和虚拟机一样重新加载一个操作系统,避免了引导、加载操作系统内核这个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载Guest OS,这个新建过程是分钟级别的,而Docker由于直接利用宿主机的操作系统则省略了这个过程,因此新建一个Docker容器只需要几秒钟。
帮助命令
docker version # 查看版本信息
docker info # 显示docker的系统信息,包括镜像和容器的数量
下面还有一些系统硬件配置的信息
docker <指令> --help # 帮助命令
当然,还需要帮助文档
https://docs.docker.com/reference/
docker images # 查看所有本地的主机上的镜像
REPOSITORY:镜像的仓库源
TAG:镜像的标签
IMAGE ID:镜像的ID
CREATED:创建的时间
SIZE:镜像的大小
docker search # 从docker hub上搜索镜像
–filter 过滤搜索结果
docker search mysql --filter=STARS=3000 # 搜索STARS大于3000的结果
docker pull # 从docker hub上下载镜像
docker pull 镜像名 [:tag版本号] 不写的tag话默认就是最新版本
指定版本下载
可以看到上面的Already exists,已经下载好的文件就可以共用,而不用再次下载,可以极大的节省内存,这就是linux联合文件系统的优点。
docker rmi 删除镜像
docker rmi -f 镜像id # 删除指定的容器
docker rmi -f 镜像id 镜像id # 删除多个容器
docker rmi -f $(docker images -aq) # 删除全部的容器
说明:有了镜像才可以创建容器,Linux,下载一个centos镜像(75.4MB)来测试学习。
docker pull centos
新建容器并启动
docker run [可选参数] image
# 参数
--name="Name" 容器名字 tomcat01 tomcat02,用来区分容器
-d 后台方式运行
-it 使用交互方式运行,进入容器查看内容
-p 指定容器的端口 -p 8080:8080
-p ip:主机端口:容器端口
-p 主机端口:容器端口
-p 容器端口
容器端口
-p 随机指定端口
docker run -it centos /bin/bash
启动并进入容器
在容器内 使用 ls
指令发现和外部其实是一样的,这就是一个小型的服务器
服务器
退出并停止容器 exit
退出容器控制台 不停止容器 ctrl + p + q
查看运行中的容器
docker ps # 查看当前正在运行的容器
docker ps -a # 查看 当前 + 历史 运行的容器
docker ps -n=n # 显示最近创建的n个容器
-q # 只显示容器的编号
删除容器
docker rm 容器id # 不能删除正在运行的容器,如果要删除的话需要加 -f
docker rm -f $(docker ps -aq)
启动和停止容器
docker start 容器id # 启动容器
docker restart 容器id # 重启容器
docker stop 容器id # 停止当前正在运行的容器
docker kill 容器id # 强制停止当前容器
# 命令 docker run -d 镜像名:
docker run -d centos
我们发现 centos 停止了
原因: docker 容器使用后台运行,就必须要有一个前台进程(比如说 -it 的那个界面就是前台应用),docker发现没有应用,就会自动停止
docker logs
docker logs -tf -tail N 容器Id # 查看指定容器的最新N条记录
# 参数解释
-t # 日志加时间
-f # 保留打印窗口,持续打印
--tail N # 显示最后的N行
docker top 容器Id
UID
PID
PPID
C
STIME
TTY
当前用户
当前进程ID
父进程ID
CPU 使用率
开始时间
终端
docker inspect 容器ID
# 我们通常容器都是使用后台方式运行的,需要进入,修改一些配置
# 方式一
docker exec -it 容器ID
# 方式二
docker attach 容器ID
区别:
docker exec
进入容器后开启一个新的终端,可以在里面操作(常用)
docker attach
进入容器正在进行的终端,不会启动新的进程
docker cp 容器ID:/路径/文件 主机的位置
# 案例
[root@e9e64b2c885b /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@e9e64b2c885b /]# cd /home
[root@e9e64b2c885b home]# ls
[root@e9e64b2c885b home]# touch test.txt
[root@e9e64b2c885b home]# ls
test.txt
[root@e9e64b2c885b home]# exit
exit
[root@iZf8zflm213bcx02dl4vxeZ ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e9e64b2c885b centos "/bin/bash" 31 hours ago Exited (0) 4 seconds ago strange_kapitsa
[root@iZf8zflm213bcx02dl4vxeZ ~]# docker cp e9e64b2c885b:/home/test.txt /home
[root@iZf8zflm213bcx02dl4vxeZ ~]# cd /home
[root@iZf8zflm213bcx02dl4vxeZ home]# ls
test.txt
命令图
docker search Nginx
docker pull Nginx
(注意: 镜像名一定要小写)docker images
docker run -d --name nginx01 -p 3344:80 nginx
-p 宿主机端口:容器内端口
外网访问
# 官方文档的安装方式
docker run -it --rm tomcat:9.0
# 属性解释
-it # 后台运行
--rm # 运行之后立刻把容器删除,用于测试
用这种方式启动的容器,一旦退出就会被删除
CTRL C 停止服务,使用docker ps 查看记录,并无此记录,不过镜像还是在的
docker images
查看镜像发现 tomcat 还在
正常启动 tomcat
值得注意的是:当你的容器镜像不是最新版的时候,若不带版本号,docker就会到docker hub上面给你下载了最新版然后启动。
访问tomcat
为什么会是404页面而不是tomcat欢迎页面呢?
由于docker镜像默认是最小的镜像,所有不必要的文件都剔除了,保证最小可运行的环境,因此webapps目录下是空白的,我们可以通过手动往webapps目录中添加文件即可。项目的发布也是如此。
docker run -d -p 8088:9000
–restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
在外网中打开(http://Ip/端口号),第一次加载会比较久
加载出来后,第一次登录需要设置密码
选择本地连接
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于环境开发的软件,它包括运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
所有的应用都可以直接打包成docker镜像,放到容器中运行
镜像的获取可通过远程仓库下载或者自己制作(DockerFile)
UnionFS (联合文件系统)
UnionFS(联合文件系统):UnionFS是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。UnionFS是Docker镜像的基础,镜像可以通过分层来进行继承,基于基础镜像,可以制作各种具体的应用镜像。
特性:一次可以同时加载多个文件系统,但从外面看起来,智能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包括所有底层的文件和目录。
docker commit 提交容器成为一个新的镜像
# 与git相似
docker commit -m="提交的描述信息" -a="读者" 容器id 新的镜像名:[tag]
案例:创建一个自己的tomcat
我们发现tomcat默认是没有欢迎页面的,我们需要加上去
外网访问,出现欢迎页面,这就是我们想要的tomcat
docker commit -a="Aldrich" -m="add an index for tomcat" 3397174e6c52 mytomcat
原理:UnionFS,在原本的tomcat基础上加多了一层再发布
docker 进阶
思考:在前面的学习中,我们知道,当容器运行时,数据都是存储在了容器内部的文件系统。那么当你运行 docker rm
命令的时候,容器将会连同它的文件系统一并被销毁。若这部分是有用的数据呢?比如说,上面放的是一个MySQL容器,我不希望数据会在容器销毁时消失。那唯一的解决办法就是别让数据只存到容器的文件系统,还应该保存一份到了宿主机。也就是将容器中的数据同步到本地。
这就是卷技术,目录的挂载,将我们的容器内的目录,挂载到宿主机上面。
容器的持久化与同步操作,容器间的数据共享。
方式一:直接使用命令来挂载 -v
docker run -it -v 主机目录:容器目录
使用 docker inspect 查看挂载信息
已经实现了双向绑定
在主机这边修改文件也可以同步到容器中
以后修改配置文件只需要在本地修改,可以自动同步到容器中!
思考:MySQL的数据持久化,不能当容器摧毁时,数据也丢失
docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root --name mysql01 mysql
#-d 后台启动
#-p 端口映射
# -v 可以写多个
# -e 配置环境
# mysql创建的时候需要配置密码
这时候服务已经启动成功了,我们来测试连接
在测试连接的时候出现了一个小插曲,数据库可视化工具报密码错误,但是通过dos窗口确实是可以登录的,无奈之下,将密码修改了一遍,就可以了。
我们来检查一下,是否已经将数据同步了
可以看到数据已经同步过来了,接下来我们要做一个测试,新建一个数据库
查看data中是否同步
思考:将mysql容器删除,数据是否还保留在宿主机?
数据依然保留在本地
上面我们使用 -v 的挂载方式是属于 指定路径挂载 ,除此之后还有两种挂载的方式:具名挂载与匿名挂载
匿名挂载
# 匿名挂载
-v 容器内路径
docker run -d -P --name nginx01 -v /ect/nginx nginx
-P # 使用随机端口
使用docker volume ls
查看所有volume 的情况
可以看到没有名称,这就是匿名挂载
具名挂载
-v 名称:容器内路径
docker run -d -P --name nginx02 -v hasName-nginx:/etc/nginx nginx
可以在列表中看到是具体的名称
查看一下这个卷的详细信息
docker volume inspect hasName-nginx
所有的Docker容器内的卷,在没有指定宿主机路径的情况下,都是放在/var/lib/docker/volumes/.../_data
中
我们通过具名挂载可以方便的找到我们定义的卷,大多数情况都是使用 具名挂载
# 通过 -v 容器内路径:ro 或者 rw 可以改变读写权限
ro # readOnly 只读
rw # read write 读写
# 例如
docker run -d -P --name nginx03 -v hasName-nginx:/etc/nginx:ro nginx
注意的是:一旦设置了容器的权限,容器对挂载内容就有限制!
设置了 ro 表示这个路径只能通过宿主机来改修,容器内部无法修改!
Dockerfile 是什么?
在之前,我们提交镜像是通过 docker commit
指令来手动创建的。Dockerfile 是一种命令脚本,用于创建 docker 镜像。
创建一个Dockerfile文件
# 创建了一个dockerfile文件,名字随意
# 文件中的内容 指令(大写!) 参数
# 命令是分层的,如同UnionFS,一层一层的构建
FROM centos
# 挂载目录
VOLUME ["volume01","volume02"]
CMD echo "----end----"
CMD /bin/bash
执行Dockerfile文件
镜像生成成功
查看挂载的目录
这属于匿名挂载,我们可以通过查看详细信息的方式来获取挂载的路径
创建镜像是常有的操作,主要使用的方式是Dockerfile
docker build
构建成为一个镜像docker run
运行镜像docker push
发布镜像(阿里云或者docker hup)每个关键字都必须是大写字母!
从上到下的顺序执行
# 表示注解
每个指令都会创建一个新的镜像层并提交
FROM # 基础镜像,一切从这里开始
MAINTAINER # 镜像是谁写的 姓名+邮箱
RUN # 镜像构建的时候需要运行的命令
ADD # 需要添加的内容 如:centos + tomcat
WORKDIR # 镜像的工作目录
VOLUME # 挂载的目录
EXPOSE # 暴露端口 -p
CMD # 指定容器启动时进行的命令,指令会替换
ENTRYPOINT # 指定容器启动时进行的命令,指令追加在后面
ONBUILD # 当构建一个被继承 Dockerfile 时会运行ONBUILD指令,事件机制
COPY # 类似ADD,将命令拷贝到镜像中
ENV # 构建的时候设置环境变量
# 由于默认的centos太纯净了,vim、clear 等常用指令都没有,我们需要手动创建一个
FROM centos # 基于centos镜像进行包装
MAINTAINER aldrich # 作者
ENV MYPATH /user/local # 指定环境变量
WORKDIR $MYPATH # 设置工作目录
RUN yum -y install vim # 安装vim
RUN yum -y install net-tools # 安装net-tools
EXPOSE 80 # 暴露端口
CMD echo $MYPATH # 打印一下环境变量
CMD echo "----end-----" # 提示结束
CMD /bin/bash # 进入/bin/bash
docker build -f 文件路径 -t 镜像名:[tag] 生成路径
docker build -f mycentos -t mycentos:1.0 .
运行测试
可以通过 docker history 容器ID
的方式来查看镜像构建步骤
前面有说到,容器数据卷可以作为容器间的数据共享。
--volumes-from # 与其它容器建立数据共享关系
docker01创建的内容同步到了docker02
同理docker02创建的数据也可以同步到docker01
**思考:**当docker01被删除之后,docker02中的数据会丢失吗?
答案是不会,当还有一个容器使用该数据,共享的数据就不会丢失。
原理图:
与Java中的引用类型赋值相似,所以当docker01被删除了,不影响docker02
结论:
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止,一旦持久化到本地,本地的数据是不会删除的。