Docker
Docker概述
DevOps: 开发运维
本质:所有的技术都是因为出现了问题,我们需要去解决,才去学习
Docker的思想就来自于集装箱
开发---运维
传统 开发人员开发一个jar给运维人员,运维人员去搭建环境
现在 开发人员将环境和jar文件打包部署上线,一套流程做完(使用docker)
例如 使用java写一款apk, 发布到应用商店 某人在应用商店安装apk---安装即可用
但是 使用java 写一个jar (环境) 之后可以带上环境打包项目(称之位镜像) --- 将镜像存放到Docker仓库(商店) 其他人可以下载我们所发布的镜像直接运行即可
如果在操作系统中运行java的时候产生了端口冲突等等情况,则会导致报错
Docker的核心思想是 隔离
每个镜像(”箱子“)都是互相隔离的
而Docker 通过隔离机制可以将服务器利用到极致
Docker是基于go语言开发的
Docker能干什么
容器化技术不是模拟的完整的操作系统 只需要其核心
虚拟机技术:
传统虚拟机:虚拟出一条硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件
Docker技术:
容器内应用直接运行在宿主机的内核上,容器没有自己的内核,也没有虚拟硬件 因此非常轻便,每个容器间是互相隔离的,每个容器内都有属于自己的文件系统,互不影响
应用更快速的交付和部署
传统 : 有很多帮助文档,安装很麻烦
Docker:打包镜像发布测试,可以一键运行
更便捷的升级和扩缩容
更简单的系统运维
在容器化之后,我们的开发、测试环境都是高度一致的
更高效的计算资源利用
Docker是内核级别的虚拟化,可以在一个物理机上运行很多容器实例
镜像(****image)
docker镜像就好比是一个模板,可以通过这个模板来创建容器服务
tomcat镜像 ===> run ==> tomcat01容器(提供服务器)
通过这些镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中)
容器(container)
Docker利用容器技术,独立运行一个或者一个组应用(通过镜像来创建的)
可以将这个容器理解为一个简易的Linux操作系统
仓库(repository)
仓库就是存放镜像的地方
分为私有仓库和公有仓库
Docker Hub 默认是国外的
Docker的安装
在centos7上:
#1、先卸载以前安装的旧版本:
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
#2、下载需要安装的安装包
yum install -y yum-utils
#3、设置镜像的仓库
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo #该地址是国外的,下载的时候很慢
#建议使用国内地址:
yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#更新软件包的索引:
yum makecache fast
#4、安装docker的相关内容 docker-ce为社区版 docoer-ee为企业版
yum install docker-ce docker-ce-cli containerd.io
#5、启动docker
systemctl start docker
#6、可以使用docker version 来查看docker的版本
#1、运行hello-world
docker run hello-world
没有hello-world 去官方网站下的library目录下pull(拉取)
拉取到之后会有一个签名信息代表其拉取成功
#8、查看下载的hello-world 镜像
[root@localhost /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 8 months ago 13.3kB
卸载docker:
#1、卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
#2、删除资源
rm -rf /var/lib/docker #/var/lib/docker为docker的默认安装路径
配置阿里云镜像加速
详情看视频:https://www.bilibili.com/video/BV1og4y1q7M4?p=7
回顾HelloWorld流程
底层原理
Docker是怎么工作的
Docker 是一个Client-Server 结构的系统,Docker的守护进程运行在主机上。通过Socket从客户端访问
DockerServer 接收到 Docker-Client的指令,就会执行这个命令
Docker 为什么比 Vmware快:
(其中 host OS 代表主机)
1、Docker有着比虚拟机更少的抽象层
2、Doucker使用的是物理机的内核,而Vmware需要的是Guest OS,所以说,新建一个容器的时候,Docker不需要想虚拟机一样重新加载一个虚拟机的内核,避免引导性操作。虚拟机时加载Guest OS (分钟级别) 而Docker 时利用物理机(宿主机)的操作系统,省略了复杂的过程(秒级)
Docker常用命令
Docker帮助命令
docker version #查看docker版本信息
docker info #查看docker系统信息,包括镜像和容器的数量
docker 命令 --help #查看命令帮助信息
帮助文档的地址:https://docs.docker.com/engine/reference/commandline
镜像命令
**docker images ** 查看所有本地的主机上的镜像
[root@localhost /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 8 months ago 13.3kB
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的标签
CREATED 镜像的创建时间
SIZE 镜像的大小
#可选项
-a, --all 列出所有镜像 Show all images (default hides intermediate images)
--digests Show digests
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print images using a Go template
--no-trunc Don't truncate output
-q, --quiet 只显示镜像的id # Only show numeric IDs
docker search 搜索镜像
使用filter来过滤
[root@localhost /]# docker search mysql --filter=STARS=3000
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 9969 [OK]
mariadb MariaDB is a community-developed fork of MyS… 3648 [OK]
docker pull 下载镜像
[root@localhost /]# docker pull mysql 后面可以使用[:tag]来指定安装的版本
Using default tag: latest #如果不写 tag 默认就时安装latest
latest: Pulling from library/mysql
d121f8d1c412: Pull complete #分层下载,docker image的核心 联合了文件系统
f3cebc0b4691: Pull complete
1862755a0b37: Pull complete
489b44f3dbb4: Pull complete
690874f836db: Pull complete
baa8be383ffb: Pull complete
55356608b4ac: Pull complete
dd35ceccb6eb: Pull complete
429b35712b19: Downloading 105.7MB/112.5MB
162d8291095c: Download complete
5e500ef7181b: Download complete
af7528e958b6: Download complete
Digest : sha256:dc255....................(以上内容省略) #数字签名
Status:Downloaded newer image for mysql:latest
docker.io/library/mysql:latest #真实地址
docker pull mysql 等价于 docker pull docker.io/library/mysql:latest
指定版本的时候必须要该版本在官方文档中存在:
docker pull mysql[:5.7] #指定安装5.7的版本
docker rmi 删除镜像(rm : 删除 i代表镜像)
#删除镜像的时候可以通过镜像id删除,也可以通过镜像名称来删除[root@localhost /]docker rmi -f 镜像id # 删除指定id的镜像 [root@localhost /]docker rmi -f 镜像id 镜像id 镜像id 镜像id # 可以删除多个镜像[root@localhost /]docker rmi -f $(docker images -aq) # 删除全部的容器
容器命令
说明:我们有了镜像才可以创建容器
docker pull centos[root@localhost /]# docker pull centosUsing default tag: latestlatest: Pulling from library/centos3c72a8ed6814: Pull complete Digest: sha256:76d24f3ba3317fa945743bb3746fbaf3a0b752f10b10376960de01da70685fbdStatus: Downloaded newer image for centos:latestdocker.io/library/centos:latest
新建容器并启动
docker run [可选参数] image#参数说明--name="Name" 容器名字 tomcat01 tomcat01,用来区分容器-d 后台方式运行-it 指定交互方式运行,进入容器查看内容-p 指定容器的端口 -p 8080:8080 -p ip:主机端口:容器端口 -p 主机端口:容器端口 #(最常用的一种) -p 容器端口 容器端口-p 随机指定端口#测试,启动并进入容器[root@localhost /]# docker run -it centos /bin/bash[root@75594955edd7 /]# ls #查看容器内的centos,与外部的没有关系bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var容器内其实就是自己的一个环境#其中 75594955edd7 为 容器id#从容器中退回至主机[root@75594955edd7 /]# exitexit
列出所有运行的容器
#docker ps 命令不加任何参数 #列出当前正在运行的容器 +1-a #列出当前运行的容器 和 历史运行过的容器-n=? # 显示最近创建的容器(指定个数)-q # 只显示容器的编号[root@localhost /]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES[root@localhost /]# docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES75594955edd7 centos "/bin/bash" 31 minutes ago Exited (0) 19 minutes ago hardcore_jang12cce6bbf0ac bf756fb1ae65 "/hello" 6 hours ago Exited (0) 6 hours ago xenodochial_feynman[root@localhost /]# docker ps -aq75594955edd712cce6bbf0ac
退出容器
exit # 直接停止容器并退出Ctrl + P + Q #容器不停止退出
删除容器
docker rm 容器id #删除指定的容器,不能删除正在运行的容器,需要强制删除 rm -fdocker rm -f $(docker ps -aq) #删除所有的容器 (-f 是强制删除)docker ps -a -q | xargs docker rm #删除所有的容器
启动和停止容器的操作
docker start 容器id #启动容器dockers restart 容器id #重启容器docker stop 容器id #停止当前正在运行的容器docker kill 容器id #强制停止(只能停止正在运行的容器)
常用其他命令
后台启动容器
#命令docker run -d 镜像名[root@localhost ~]# docker run -d centos# 当使用docker ps 的时候,发现 centos 停止了原因:docker容器在后台运行时,必须有一个前台进程,当docker发现没有应用的时候,就会自动停止#nginx 容器启动后没发现自己没有提供服务,就会立刻停止,就是没有程序了
日志命令
[root@localhost ~]# docker logs --helpUsage: docker logs [OPTIONS] CONTAINERFetch the logs of a containerOptions: --details Show extra details provided to logs -f, --follow Follow log output --since string Show logs since timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes) --tail string Number of lines to show from the end of the logs (default "all") -t, --timestamps Show timestamps --until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes) docker logs -f -t 容器id# 查看所有的日志信息
shell编程
-c 往里面写脚本[root@localhost ~]# docker run -d centos /bin/sh -c "while true;do echo adminluo;sleep 1;done" #脚本内容和命令1518e665bc039905ab70f4293a8aea7477d5c351458defd5c6858dc8bf7e2922[root@localhost ~]# docker psCONTAINER ID IMAGE 1518e665bc03 centos #显示日志docker logs -f -t --tail 容器id--tatl 条数 #可以查看指定条数的日志,之后会一致打印
查看容器中的进程信息 在Linux中使用ps查看
[root@localhost ~]# docker top a0fde7c70ff5UID PID PPID C STIME TTY root 1619 1601 0 9月19 pts/0
查看镜像元数据
#命令docker inspect 容器id#*******************************************************************************************************[root@localhost ~]# docker inspect a0fde7c70ff5[ { "Id": "a0fde7c70ff57298d01ac3f2c4e8e69255750b898aea6de574cf452067a31464", "Created": "2020-09-19T15:45:56.012499301Z", "Path": "/bin/bash", "Args": [], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 1619, "ExitCode": 0, "Error": "", "StartedAt": "2020-09-19T15:45:56.447461022Z", "FinishedAt": "0001-01-01T00:00:00Z" }, "Image": "sha256:0d120b6ccaa8c5e149176798b3501d4dd1885f961922497cd0abef155c869566", "ResolvConfPath": "/var/lib/docker/containers/a0fde7c70ff57298d01ac3f2c4e8e69255750b898aea6de574cf452067a31464/resolv.conf", "HostnamePath": "/var/lib/docker/containers/a0fde7c70ff57298d01ac3f2c4e8e69255750b898aea6de574cf452067a31464/hostname", "HostsPath": "/var/lib/docker/containers/a0fde7c70ff57298d01ac3f2c4e8e69255750b898aea6de574cf452067a31464/hosts", "LogPath": "/var/lib/docker/containers/a0fde7c70ff57298d01ac3f2c4e8e69255750b898aea6de574cf452067a31464/a0fde7c70ff57298d01ac3f2c4e8e69255750b898aea6de574cf452067a31464-json.log", "Name": "/admiring_cray", "RestartCount": 0, "Driver": "overlay2", "Platform": "linux", "MountLabel": "", "ProcessLabel": "", "AppArmorProfile": "", "ExecIDs": null, "HostConfig": { "Binds": null, "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "default", "PortBindings": {}, "RestartPolicy": { "Name": "no", "MaximumRetryCount": 0 }, "AutoRemove": false, "VolumeDriver": "", "VolumesFrom": null, "CapAdd": null, "CapDrop": null, "Capabilities": null, "Dns": [], "DnsOptions": [], "DnsSearch": [], "ExtraHosts": null, "GroupAdd": null, "IpcMode": "private", "Cgroup": "", "Links": null, "OomScoreAdj": 0, "PidMode": "", "Privileged": false, "PublishAllPorts": false, "ReadonlyRootfs": false, "SecurityOpt": null, "UTSMode": "", "UsernsMode": "", "ShmSize": 67108864, "Runtime": "runc", "ConsoleSize": [ 0, 0 ], "Isolation": "", "CpuShares": 0, "Memory": 0, "NanoCpus": 0, "CgroupParent": "", "BlkioWeight": 0, "BlkioWeightDevice": [], "BlkioDeviceReadBps": null, "BlkioDeviceWriteBps": null, "BlkioDeviceReadIOps": null, "BlkioDeviceWriteIOps": null, "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpusetCpus": "", "CpusetMems": "", "Devices": [], "DeviceCgroupRules": null, "DeviceRequests": null, "KernelMemory": 0, "KernelMemoryTCP": 0, "MemoryReservation": 0, "MemorySwap": 0, "MemorySwappiness": null, "OomKillDisable": false, "PidsLimit": null, "Ulimits": null, "CpuCount": 0, "CpuPercent": 0, "IOMaximumIOps": 0, "IOMaximumBandwidth": 0, "MaskedPaths": [ "/proc/asound", "/proc/acpi", "/proc/kcore", "/proc/keys", "/proc/latency_stats", "/proc/timer_list", "/proc/timer_stats", "/proc/sched_debug", "/proc/scsi", "/sys/firmware" ], "ReadonlyPaths": [ "/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger" ] }, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/451d8726897aa1cd0dc868048e16d636c8a173e337a41dea7d00c38226cf4a95-init/diff:/var/lib/docker/overlay2/fc936bee709b8fa91a06b278c9d89dd521ca6e06943694740d8d0327095d93b5/diff", "MergedDir": "/var/lib/docker/overlay2/451d8726897aa1cd0dc868048e16d636c8a173e337a41dea7d00c38226cf4a95/merged", "UpperDir": "/var/lib/docker/overlay2/451d8726897aa1cd0dc868048e16d636c8a173e337a41dea7d00c38226cf4a95/diff", "WorkDir": "/var/lib/docker/overlay2/451d8726897aa1cd0dc868048e16d636c8a173e337a41dea7d00c38226cf4a95/work" }, "Name": "overlay2" }, "Mounts": [], "Config": { "Hostname": "a0fde7c70ff5", "Domainname": "", "User": "", "AttachStdin": true, "AttachStdout": true, "AttachStderr": true, "Tty": true, "OpenStdin": true, "StdinOnce": true, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/bin/bash" ], "Image": "centos", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": { "org.label-schema.build-date": "20200809", "org.label-schema.license": "GPLv2", "org.label-schema.name": "CentOS Base Image", "org.label-schema.schema-version": "1.0", "org.label-schema.vendor": "CentOS" } }, "NetworkSettings": { "Bridge": "", "SandboxID": "9e022abafa3557d84e31eec697f58d66ba509e054256efa9c8a4a12ea2337d28", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": {}, "SandboxKey": "/var/run/docker/netns/9e022abafa35", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "5c9eaef03e4e93c9601ed900a3dc918c51838b46be3c6de2f4f006e1f92c738a", "Gateway": "172.17.0.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "MacAddress": "02:42:ac:11:00:02", "Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "d0a7bd76c17d0bf2769f34b9565e51a3ee105a65dbfecc9cff0316ceb798ffee", "EndpointID": "5c9eaef03e4e93c9601ed900a3dc918c51838b46be3c6de2f4f006e1f92c738a", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:02", "DriverOpts": null } } } }]
进入当前正在运行的容器
#方式一#命令 docker exec -it 容器id bashshell 【it是以交互模式运行,bashshel是容器运行的环境】[root@localhost ~]# docker exec -it a9912c6c820a /bin/bash[root@a9912c6c820a /]# lsbin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var[root@a9912c6c820a /]# ps -efUID PID PPID C STIME TTY TIME CMDroot 1 0 0 01:01 pts/0 00:00:00 /bin/bashroot 14 0 0 01:02 pts/1 00:00:00 /bin/bashroot 28 14 0 01:07 pts/1 00:00:00 ps -ef#方式二docker attach 容器id#测试[root@localhost ~]# docker attach a9912c6c820a#docker exec 是进入容器后开启一个新的终端,可以在里面操作#docker attach 进入容器正在执行的终端,不会开启新的进程
拷贝文件
命令: docker cp 容器id : 文件在容器中的路径 文件在容器外的路径#在容器中的操作,新建一个文件[root@a9912c6c820a bin]# [root@a9912c6c820a bin]# cd /home[root@a9912c6c820a home]# ls[root@a9912c6c820a home]# touch testfile.php[root@a9912c6c820a home]# lstestfile.php[root@a9912c6c820a home]# exitexit[root@localhost ~]# docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESa9912c6c820a centos "/bin/bash" 34 minutes ago Exited (0) 14 seconds ago zen_wescoffa0fde7c70ff5 centos "/bin/bash" 10 hours ago Exited (0) 9 hours ago admiring_crayd9a2afc6dfc2 centos "/bin/bash" 10 hours ago Exited (0) 10 hours ago kind_neumann10d6efd94957 centos "/bin/bash" 36 hours ago Exited (0) 36 hours ago nice_black#拷贝命令[root@localhost ~]# docker cp a9912c6c820a:/home/testfile.php /home[root@localhost ~]# cd home-bash: cd: home: 没有那个文件或目录[root@localhost ~]# cd /home[root@localhost home]# lsluo st test1 test2 testfile.php user1 user2 user3#拷贝是一个手动过程 以后可以使用-v 卷的技术,可以实现自动同步
小结
练习
将80端口映射到某一个端口 通过公网的该端口可以访问到docker 的8080
[root@localhost ~]# docker run -p 3344:80 -d --name nginx01 nginxe82bb004cea5841ce2acc3f1f65ef815cc20e11df9618b13822bdf8ea932b509#-d 后台运行 --name 指定容器名字 -p 宿主机端口:容器内部端口#用-P(大写)标记时,docker会随机选择一个端口映射到容器内部开放的网络端口上。[root@localhost ~]# docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESe82bb004cea5 nginx "/docker-entrypoint.…" 9 seconds ago Up 9 seconds 0.0.0.0:3344->80/tcp nginx016f146625b78e centos "/bin/bash" About an hour ago Exited (0) 14 minutes ago gifted_panini[root@localhost ~]# curl http://localhost:3344#curl 查看url的状况,发送一个请求#进入容器[root@localhost ~]# docker exec -it nginx01 /bin/bashroot@e82bb004cea5:/# whereis nginxnginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx#切换到Linux下,查看端口占用状况[root@localhost ~]# netstat -an |grep 3344tcp6 0 0 :::3344 :::* LISTEN
[Docker容器内部端口映射到外部宿主机端口]
参考以下文章:
https://www.cnblogs.com/kevingrace/p/9453987.html
部署tomcat
#官方的使用docker run -it --rm tomcat:9.0# -- rm 解析: 我们之前的启动都是在后台,停止了容器之后,容器还是可以查到.而--rm 一般用来测试,用完就删除(删除容器,但是镜像还在)#下载之后启动docker pull tomcat#启动[root@localhost ~]# docker run -d --name tomcat01 -p 3355:8080 tomcat#该状况从外界访问会出现404错误#*****************************************************************************************#进入容器[root@localhost ~]# docker exec -it d5e5ab099f868fff524d54a19eec52598607e5ce962b38672f3eda6a54cdd235 /bin/bashroot@d5e5ab099f86:/usr/local/tomcat# lsBUILDING.txt CONTRIBUTING.md LICENSE NOTICE README.md RELEASE-NOTES RUNNING.txt bin conf lib logs native-jni-lib temp webapps webapps.dist workroot@d5e5ab099f86:/usr/local/tomcat# cd webappsroot@d5e5ab099f86:/usr/local/tomcat/webapps# lsroot@d5e5ab099f86:/usr/local/tomcat/webapps# cd ..#将webapps.dist中的所有文件全部移动到webapps中root@d5e5ab099f86:/usr/local/tomcat# cp -r webapps.dist/* webapps #-r 递归copyroot@d5e5ab099f86:/usr/local/tomcat# cd webappsroot@d5e5ab099f86:/usr/local/tomcat/webapps# lsROOT docs examples host-manager manager#可以正常访问
部署 es + kibana
es: elasticsearch6 搜索引擎kibana:es的可视化操作界面#es 暴露的端口很多#es 十分的耗内存 (全文搜索引擎)#es 的数据一般需要放置到安全目录 挂载#--net somenetwork 为 网络配置#启动elasticsearchdocker run -d --name elasticserch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
docker status 查看容器的资源占用情况
可视化
-
portainer
docker run -d -p 8088:9000 \ --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
-
Rancher (CI/CD再用)
什么是portainer?
Dokcer图形化界面管理工具,提供一个后台面板供我们操作
Docker镜像
镜像是什么
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件
所有的应用,直接打包docker镜像,就可以直接跑起来
如何得到镜像:
- 远程仓库下载
- 从别人那里拷贝
- 自己制作一个镜像dockerfile
例如:
tomcat 和 mysql ,其中mysql需要使用centos,如果下载了centos,那么tomcat就不需要再下载了,可以直接使用mysql的centos
Docker镜像加载原理
(1)UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下,Union文件系统是Dokcer镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统加载起来,这样最终的文件系统会包含所有的底层文件和目录
(2)Docker镜像加载原理
docker的镜像实际上是由一层一层的文件系统构成,这种层级的文件系统UnionFS。
主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的linux/unix系统是一样的,包含boot加载器内核。当boot加载完之后整个内核就都在内存中了,此时内存的使用权已经由bootfs交给内核了,此时系统也会卸载bootfs
对以一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就行,因为底层直接用host和kernel,自己只需要提供rootfs就行。由此可见对于不同的Linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。
由于上述原因,Docker的启动时秒级,而虚拟机的启动时分钟级别
可以使用docker image inspect 容器名 查看容器的信息
"Type": "layers", "Layers": [ "sha256:4ef54afed7804a44fdeb8cf6562c2a1eb745dcaabd38b1ac60126f0966bf6aef", "sha256:6add0d2b5482578ccb2eeed7d7dac7c4c258722884db7e69c1739fd9f69a93dc", "sha256:d37096232ed8372a371df462c953a61381c8a62424eebd8d260941a5473b0957", "sha256:17bdf5e22660221184ed52356cf4e74d5c4cd0af9ad6326c4f683b15b41621d4", "sha256:df95ed2a791dcc795f8bb4868dfac63aa2e9bb9a81697d4954e968b3990cf909", "sha256:4f17d163126ff1be561ac278bfa3510785f9b92d6c06a445518cf5764d1b595e", "sha256:8b185d674aeffdfbc67cd39ef9ce6970a615b816372575aaa64c5e8dcf343265", "sha256:eb6e8fe5c6dcab45fdddb8d87f8a860032e0b17e377b23dc5bf5dd7b639f464a", "sha256:1485ce09f58525e2feb2f46305a41b92f6ef419cb5407f4a63dc5118150e3120", "sha256:b654a29de9ee9eb506c668796e307573f7e5e9762d2fd4ecf890321577501d35" ] #以上时tomcat的所有的层,每一层对应每一个步骤
分层理解
2.特点
docker镜像都是只读的
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作“容器层”,“容器层”之下都叫“镜像层”
commit镜像
docker commit #提交容器成为一个新的副本#命令和git原理类似docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG]#启动tomcatdocker run -d --name tomcat02 -p 3355:8080 tomcat902a2d7b01ae82da6237976841759f21b6d550186271897c31e5bf0b1cc1ce99#修改容器[root@localhost ~]# docker exec -it 902a2d7b01ae /bin/bashroot@902a2d7b01ae:/usr/local/tomcat# cp -r webapps.dist/* webapps#提交容器[root@localhost ~]# docker commit -a="admin_luo" -m="add webapps app" 902a2d7b01ae tomcat02:1.0sha256:9edbfbf50c79eb10a25afe359c00bc64f25accf8bf82fc08d87907e8ae4eaa67#查看容器[root@localhost ~]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEtomcat02 1.0 9edbfbf50c79 8 seconds ago 652MB
#1、启动一个默认的tomcat#2、发现这个默认的tomcat是没有webapps应用,镜像的原因,官方的镜像默认webapps下面是没有文件的#3、我自己拷贝进去基本的文件#4、将我们操作过的容器通过commit提交为一个镜像 我们以后可以使用我们修改过的进行即可
容器数据卷
什么是容器数据卷
产生背景:如果数据都存储再容器中,那么我们的容器一旦删除,数据就会丢失。需求:数据可以持久化
mysql:一旦容器删了,其中的数据也会删除需求:mysql数据可以存储再本地
容器之间有一个数据共享的技术:Docker容器中产生的数据同步到本地
这就是卷技术,目录的挂载,将我们容器内的目录,挂载到Linux上面(一种同步机制)
容器的持久化和同步操作,容器之间也可以数据共享
使用数据卷
方式一:直接俄使用命令来挂载 -v 属性
#将容器内部的/home目录挂载到Linux上的/home/ceshi中[root@localhost ~]# docker run -it -v /home/ceshi:/home centos /bin/bash#查看挂载情况:[root@localhost ~]# docker inspect 7c536fba4548"Mounts": [ { "Type": "bind", "Source": "/home/ceshi", "Destination": "/home", "Mode": "", "RW": true, "Propagation": "rprivate" } ],
实战:安装mysql
MySQL的数据持久化问题
#获取镜像docker pull mysql:5.7
具名和匿名挂载
#匿名挂载-v 容器内路径 # 只写容器内路径则会再外部随机创建一个目录与其挂载[root@localhost ~]# docker run -d -P --name nginx01 -v /etc/nginx nginxa7821d87b202175cde7207b03065a9a937ee8501a751390fde857ff96782b2e8#查看所有volume(数据卷)的情况[root@localhost ~]# docker volume lsDRIVER VOLUME NAMElocal a80d776cc1e264df0e3453f34f5a25740087ef310cfee21089308a656c27b0dflocal cd8171e5ab3b6611b2b53b5a47aa4827f1674d8aa999facdf584a6a0624d73b9# 这种就是匿名挂载,我们在-v只写了容器内的路径,没有i写容器外的路径#具名挂载[root@localhost ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginxd0444da1c96079932c2de3fae1c86f5f929a0aea9e6a28b34453fee77efb6089[root@localhost ~]# docker volume lsDRIVER VOLUME NAMElocal a80d776cc1e264df0e3453f34f5a25740087ef310cfee21089308a656c27b0dflocal cd8171e5ab3b6611b2b53b5a47aa4827f1674d8aa999facdf584a6a0624d73b9local juming-nginx#通过 -v 卷名:容器内路径#查看以下这个卷[root@localhost ~]# docker inspect juming-nginx[ { "CreatedAt": "2020-09-30T11:22:41+08:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data", #路径 "Name": "juming-nginx", "Options": null, "Scope": "local" }]
所有的docker容器内的卷,没有指定目录的情况下都时在var/lib/docker/volumes/xxxx(卷名)/_data
通过具名挂载可以方柏霓我们找到一个卷,大多数情况在使用具名挂载
#如何确定时具名挂载还是匿名挂载,还是指定路径挂载-v 容器内路径 #匿名挂载-v 卷名:容器内路径 #具名挂载-v /宿主机路径:容器内路径 #指定路径挂载
拓展
#通过 -v 容器内路径:ro rw 改变读写权限ro readonly #只读rw readwrite #可读可写#一旦设置了容器权限,容器对我们挂载出来的内容就有了限定docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginxdocker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx#ro说明这个路径只能通过宿主机来操作,容器内部无法操作
DockerFile
初识dockerfile
Dockerfile就是用来docker镜像的构建文件,命令脚本
通过这个脚本可以生成镜像,镜像是一层一层的,脚本一个个的命令,每个命令都是一层
#创建一个dockerfile文件,名字可以随意#文件中的内容 指令(大写) 参数FROM centosVOLUME ["volume01","volume02"] #在创立的时候就将其挂载出来。【匿名挂载】CMD echo "------end-----"CMD /bin/bash#这里的每一个命令就是镜像的一层 # . 代表生成在当前目录下
这个卷和外部一定有一个同步的目录
[root@13c2a5ed112f /]# cd volume01[root@13c2a5ed112f volume01]# touch testfile[root@13c2a5ed112f volume01]# lstestfile[root@13c2a5ed112f volume01]# exitexit[root@localhost dockerfile-test]# docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES13c2a5ed112f 923f2bcbcaf0 "/bin/bash" 8 minutes ago Exited (0) About a minute ago unruffled_bhaskarad0444da1c960 nginx "/docker-entrypoint.…" 8 hours ago Exited (0) 7 hours ago nginx02a7821d87b202 nginx "/docker-entrypoint.…" 8 hours ago Exited (0) 7 hours ago nginx01[root@localhost dockerfile-test]# docker inspect 13c2a5ed112f
[root@localhost dockerfile-test]# cd /var/lib/docker/volumes/7c295609fb1a192c2aded5e6869b19b0db428e16b0d7710c19f295c593de0179/_data[root@localhost _data]# lstestfile
可以发现,在容器中创建的文件在容器外也可以访问
如果构建镜像的时候没有挂载卷,需要手动镜像挂载: -v 卷名:容器内路径
数据卷容器
多个mysql同步数据
利用父容器给别的容器共享数据
#启动刚才创建的容器来进行实验:
通过--volumes-from可以实现容器之间的数据共享
#创建一个docker02 并使用--volumes-from docker01 docker01中的操作:[root@abc9d6979c45 volume01]# touch docker01[root@abc9d6979c45 volume01]# lsdocker01#在docker01中创建一个文件:在docker02中可以看到:如下图在docker02中创建文件,在docker01中也可以看到
将docker01删除之后,docker02依然可以访问这个文件
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为之
但是一旦持久化到了本地,这个时候,本地的数据不会删除
Dockerfile
dockerfile是用来构建docker镜像的文件,命令参数脚本
构建步骤
1、编写一个dockerfile文件
2、docker build 构建成为一个镜像
3、docker run 运行镜像
4、docker push发布镜像(DockerHub、阿里云镜像仓库)
很多官方镜像都是基础包,很多功能都没有。我们通常会自己搭建自己的镜像
DockerFile构建过程
基础知识
- 每个保留关键字(指令)都必须是大写字母
- 执行顺序为从上到下
-
表示注释
- 每个指令都会创建提交一个新的镜像层并提交
dockerfile是面向开发的,我们以后发布项目(做镜像)就需要编写dockerfile文件
docker镜像逐渐成为企业交付的标准,必须要掌握
dockerfile的指令
FROM #基础镜像,一切从这里开始构建MAINTAINER #镜像是谁写的,姓名+邮箱RUN #镜像构建的时候需要运行的命令ADD #步骤:tomcat镜像,这个tomcat压缩包 添加内容WORKDIR #镜像的工作目录VOLUME #挂载的目录EXPOSE #暴露端口配置CMD #指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代ENTRYPOINT #指定这个容器启动的时候要运行的命令,可追加命令ONBUILD #当构建一个被继承DockerFile,这个时候就会运行ONBUILD的指令(触发指令)COPY #类似ADD,将我们的文件拷贝到镜像中ENV #构建的时候设置环境变量
实战测试
Docker Hub中99%的镜像都是从 scratch 这个基础镜像过来的,然后配置需要的软件和配置来进行构建
创建一个自己的centos
编写一个Dockerfile的文件[root@localhost dockerfile]# vim dockerfile[root@localhost dockerfile]# cat dockerfile FROM centosMAINTAINER luoENV MYPATH /usr/localWORKDIR $MYPATHRUN yum -y install vimRUN yum -y install net-tooldEXPOSE 80CMD echo $MYPATHCMD echo "----end----"CMD /bin/bash# 2、通过这个文件构建镜像#命令 docker build -f dockerfile文件路径 -t 镜像名[版本号][root@localhost dockerfile]# docker build -f mydockerfile-centos -t mycentos .Successfully built 5008b70c630dSuccessfully tagged mycentos:latest#3、测试运行[root@localhost dockerfile]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEmycentos latest 5008b70c630d 8 minutes ago 295MB[root@localhost dockerfile]# docker run -it mycentos[root@7c219fc55116 local]# pwd/usr/local #该目录是之前设置的工作目录,若没有设置,默认是根目录
docker history 可以列出本地进行的变更历史
CMD 和 ENTRYPOINT区别
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代ENTRYPOINT #指定这个容器启动的时候要运行的命令,可以追加命令
[root@localhost dockerfile]# vim dockerfile-cmd-testFROM centosCMD ["ls","-a"][root@localhost dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .[root@localhost dockerfile]# docker run -it a34f818465ec. .dockerenv dev home lib64 media opt root sbin sys usr.. bin etc lib lost+found mnt proc run srv tmp var#想追加一个命令 -l ls -al会报错:[root@localhost dockerfile]# docker run a34f818465ec -ldocker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"-l\": executable file not found in $PATH": unknown.#cmd的清理下 -l 替换了CMD["ls","-a"]命令。 -l 不是命令所以会产生报错
测试ENTRYPOINT
[root@localhost dockerfile]# vim dockerfile-cmd-entrypointFROM centosENTRYPOINT ["ls","-a"][root@localhost dockerfile]# docker build -f dockerfile-cmd-entrypoint -t entroypoint-test[root@localhost dockerfile]# docker build -f dockerfile-cmd-entrypoint -t entroypoint-test .Sending build context to Docker daemon 4.096kBStep 1/2 : FROM centos ---> 0d120b6ccaa8Step 2/2 : ENTRYPOINT ["ls","-a"] ---> Running in 9b686907bb2dRemoving intermediate container 9b686907bb2d ---> ef7c96ff3b31Successfully built ef7c96ff3b31Successfully tagged entroypoint-test:latest[root@localhost dockerfile]# docker run entroypoint-test....dockerenvbindevetchomeliblib64lost+foundmediamntoptprocrootrunsbinsrvsystmpusrvar#追加命令是直接在ENTRYPOINT后面的[root@localhost dockerfile]# docker run entroypoint-test -ltotal 0drwxr-xr-x. 1 root root 6 Oct 2 12:02 .drwxr-xr-x. 1 root root 6 Oct 2 12:02 ..-rwxr-xr-x. 1 root root 0 Oct 2 12:02 .dockerenvlrwxrwxrwx. 1 root root 7 May 11 2019 bin -> usr/bindrwxr-xr-x. 5 root root 340 Oct 2 12:02 devdrwxr-xr-x. 1 root root 66 Oct 2 12:02 etcdrwxr-xr-x. 2 root root 6 May 11 2019 homelrwxrwxrwx. 1 root root 7 May 11 2019 lib -> usr/liblrwxrwxrwx. 1 root root 9 May 11 2019 lib64 -> usr/lib64drwx------. 2 root root 6 Aug 9 21:40 lost+founddrwxr-xr-x. 2 root root 6 May 11 2019 mediadrwxr-xr-x. 2 root root 6 May 11 2019 mntdrwxr-xr-x. 2 root root 6 May 11 2019 optdr-xr-xr-x. 133 root root 0 Oct 2 12:02 procdr-xr-x---. 2 root root 162 Aug 9 21:40 rootdrwxr-xr-x. 11 root root 163 Aug 9 21:40 runlrwxrwxrwx. 1 root root 8 May 11 2019 sbin -> usr/sbindrwxr-xr-x. 2 root root 6 May 11 2019 srvdr-xr-xr-x. 13 root root 0 Oct 2 06:04 sysdrwxrwxrwt. 7 root root 145 Aug 9 21:40 tmpdrwxr-xr-x. 12 root root 144 Aug 9 21:40 usrdrwxr-xr-x. 20 root root 262 Aug 9 21:40 var
Dockerfile中许多命令十分相似,我们需要了解其区别,最好是对比学习
实战:tomcat镜像
1、准备镜像文件 tomcat压缩包,jdk的压缩包
2、编写dockerfile文件 , 官方名命Dokcerfile,build 的时候会自动寻找这个文件,就不需要-f进行指定了
[root@localhost tomcat]# cat Dockerfile FROM centosMAINTAINER luoxyCOPY readme.txt /usr/local/readme.txtADD jdk-8u251-linux-x64.tar.gz /usr/localADD apache-tomcat-9.0.38.tar.gz /usr/localRUN yum -y install vimENV MYPATH /usr/localWORKDIR $MYPATHENV JAVA_HOME /usr/local/jdk1.8.0_251ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jarENV CATALINA_HOME /usr/local/apache-tomcat-9.0.38ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.38ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/binEXPOSE 8080CMD /usr/local/apache-tomcat-9.0.38/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.38/bin/logs/catalina.out
使用 ADD会自动解压
CATALINA 为toncat 的默认目录
3、构建镜像
#docker build -t diytomcat .
4、启动镜像
[root@localhost tomcat]# docker run -d -p 9090:8080 --name luoxytomcat -v /home/luoxy/build/tomcat/test:/usr/local/apache-tomcat-9.0.38/webapps/test -v /home/luoxy/build/tomcat/tomcatlogs:/usr/local/apache-tomcat-9.0.38/logs diytomcat1bf0c4d1df0d2e65f11acc90a9d51f945f06f6750319c0df2aabd29380e36872
5、访问测试
6、发布项目(由于做了卷的挂载,我们可以直接在本地发布项目)
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"></web-app>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html><html><head><meta charset="utf-8"><title>web logs</title></head><body>Hello World!<br/><%System.out.println("------my test web logs-----");%></body></html>
通过以上步骤,项目部署成功
发布自己的镜像
Dockerhub
1、地址: https://hub.docker.com/
2、在centos中提交镜像
[root@localhost ~]# docker login --helpUsage: docker login [OPTIONS] [SERVER]Log in to a Docker registry.If no server is specified, the default is defined by the daemon.Options: -p, --password string Password --password-stdin Take the password from stdin -u, --username string Username
3、登录完毕之后就可以提交镜像了
[root@localhost ~]# docker login -u 1297725225Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json.Configure a credential helper to remove this warning. Seehttps://docs.docker.com/engine/reference/commandline/login/#credentials-storeLogin Succeeded#提交前需要先修改镜像名:[root@localhost ~]# docker tag f1fca8e2d444 1297725225/tomcat[root@localhost ~]# docker push 1297725225/tomcatThe push refers to repository [docker.io/1297725225/tomcat]dbe8804e9957: Pushed b5079a1d0008: Pushed 285cb2d1a9e3: Pushing [=========================> ] 203MB/405.8MBbff150372ed8: Pushed 291f6e44771a: Pushed
小结
Docker网络
企业实战
Docker Compose
Docker Swarm
CI/CD Jenkins 流水线
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现