,
Docker使用
Docker简介
Docker是一个用来装应用的容器,就像杯子可以装水,笔筒可以放笔,书包可以放书,可以把hello word放在Docker中,可以把网站放入Docker中,可以把任何想得到的程序放在Docker中.
Docker解决的问题?
-
系统环境不一致
开发:我本地没问题.运维:服务器没问题. 这个问题就变成了皮球。下面docker来了,它把操作系统,jdk,tomcat,代码,配置全部放到集装箱里.再打包放到鲸鱼上,由鲸鱼给我们送到服务器上,在我的机器上怎么运行,在别的机器上也怎么运行.不会有任何的问题.一句话就是docker解决了运行环境不一致所带来的问题.
-
隔离问题
因为Linux本身就是一个多用户的操作系统本身就可以供多个用户同时使用。然而docker的隔离性可以解决这个问题,就算别人的程序还是死循环疯狂吃CPU,还是疯狂打日志把硬盘占满,还是内存泄漏,把内存占满,都不会导致我们的程序运行错误.因为docker在启动的时候就限定好了,它最大使用的CPU硬盘,如果超过了,就会杀掉对应进程.
-
方便扩容
大部分系统业务量并不是每天都比较平均的,特别是一些电商系统,每天总有那么几天业务量是平时的几倍甚至几十倍,如果按双11的规模去准备服务器那么对于平时的规模来说又是极大的浪费,所以就在节日前临时扩展机器,过完节再把多余的节点下线,这就给运维带来了非常大的工作量,一到过节就在各个机器上部署各种各样的服务,我们启动程序需要java,tocmat等等,并且还可能起不来还要调试,这是非常恶心的工作,有了docker一切都变得美好了,只要点一下服务器就可以从10台变成100台甚至1000,1W台.都是分分钟的事情
Docker的基本组成
-
仓库(Repository)
仓库是存放镜像的地方,总共分为
共有仓库
(所有人可以访问)和私有仓库
(只有自己可以访问) -
镜像(image)
Docker镜像是提前制作好的模板,类似的有tomcat镜像从仓库里面拉去下来可以直接运行
-
Container(容器)
执行运行镜像的命令时候就是运行在容器里面,容器容器相互隔离,降低了软件与软件的耦合性
使用流程是
仓库->镜像->容器
就是从仓库拉取进行本地运行在容器当中
安装Docker
安装命令
环境查看 cat /etc/os-release 我的是CentOS7
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XrxW6zCe-1631176874108)(https://i.loli.net/2021/04/19/M13KLCWAQqpcV6o.png)]
#1.卸载旧的Docker版本
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 \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#4.更新软件包索引
yum makecache fast
#5.安装Docker docker-ce(社区版)
yum install docker-ce docker-ce-cli containerd.io
#6.查看Docker是否安装成功 显示版本说明安装成功
docker version
#7.启动Docker
systemctl start docker
#8.卸载Docker(了解)
#8.1卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
#8.2删除资源
rm -rf /var/lib/docker
rm -rf /var/lib/containerd
运行一个Docker程序
#1.运行这个镜像如果本地没有则从远程镜像仓库下载
docker run hello-world
#2.查看本地镜像
docker image
配置阿里云镜像加速
登录自己的阿里云账号然后访问下面的网站然后复制加速地址,四个命令挨个执行(也要复制sudo)
https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["填写你自己的地址"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
docker run hello-world流程
Docker常用命令
帮助命令
# docker版本
docker version
# docker详情
docker info
# docker帮助命令
docker --help
# 查看容器的内存cpu占用情况
docker states
镜像命令
docker images 查看所有的本地镜像
镜像仓库源 标签 镜像id 镜像创建时间 镜像大小
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 7 weeks ago 13.3kB
docker search mysq 搜索镜像l
镜像名称 描述 点赞
NAME DESCRIPTION STARS
mysql MySQL is a widely used, open-source relation… 10777
mariadb MariaDB Server is a high performing open sou… 4058
docker pull mysql 下载镜像
# 下载镜像 docker pull 镜像名[:tag]
[root@pinyoyougou-docker /]# docker pull mysql[:tag]
Using default tag: latest # 如果不些tag,默认就是最新版
latest: Pulling from library/mysql
f7ec5a41d630: Pull complete # 分享下载,docker image的核心 联合文件系统
9444bb562699: Pull complete
6a4207b96940: Pull complete
181cefd361ce: Pull complete
8a2090759d8a: Pull complete
15f235e0d7ee: Pull complete
d870539cd9db: Pull complete
493aaa84617a: Pull complete
bfc0e534fc78: Pull complete
fae20d253f9d: Pull complete
9350664305b3: Pull complete
e47da95a5aab: Pull complete
Digest: sha256:04ee7141256e83797ea4a84a4d31b1f1bc10111c8d1bc1879d52729ccd19e20a
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest #真正的下载地址
# 指定版本下载
[root@pinyoyougou-docker /]# docker pull mysql:5.7
5.7: Pulling from library/mysql
f7ec5a41d630: Already exists #因为之前下载过mysql 所以已经存在的文件就不需要下载
9444bb562699: Already exists
6a4207b96940: Already exists
181cefd361ce: Already exists
8a2090759d8a: Already exists
15f235e0d7ee: Already exists
d870539cd9db: Already exists
cb7af63cbefa: Pull complete
151f1721bdbf: Pull complete
fcd19c3dd488: Pull complete
415af2aa5ddc: Pull complete
Digest: sha256:a655529fdfcbaf0ef28984d68a3e21778e061c886ff458b677391924f62fb457
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
删除镜像
[root@pinyoyougou-docker /]# docker rmi -f 0627ec6901db
容器命令
新建容器并启动
docker run [可选参数] image
# 参数署命
--name="Myname" #给容器起一个自己的名字
-d #后台方式运行
-it #进入容器内部
-p #指定容器的端口 8080:8080
#测试 启动容器并进入容器
[root@pinyoyougou-docker /]# docker run -it centos /bin/bash
#进入容器内部发现root@后面内容改变
[root@2f5ce69a584c /]#
#从容器推出
[root@2f5ce69a584c /]# exit;
列出所有运行容器
# docker ps 命令
-a #列出当前正在运行的容器+带出历史运行过的容器
-n=5 #列出最近创建的5个容器
# 查看正在运行的容器
[root@pinyoyougou-docker /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 查看正在运行的容器和历史运行过的容器
[root@pinyoyougou-docker /]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f5ce69a584c centos "/bin/bash" 7 minutes ago Exited (127) 9 seconds ago nervous_chaum
退出容器
exit # 直接停止容器并推出
Ctrl +P +Q # 容器不停止退出
删除容器
docker rm 容器id # 删除指定的容器,不能删除正在运行的容器 如果要删除需要先停止容器 docker stop 容器id
启动和停止容器
docker start 容器id # 启动容器
docker stop 容器id # 停止当前正在运行的容器
docker restart 容器id #重启容器
docker kill 容器id #强制停止重启
常用其他命令
后台启动容器
# 通过-d 后台方式运行容器
[root@pinyoyougou-docker /]# docker run -d centos
f9d39ffbbbb2d2547ffd5707ed49cef41bc307dfeab3cf1b1817d70d4f9c8379
# 发现容器并没有运行
[root@pinyoyougou-docker /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 常见的坑: docker 容器使用后台运行,就必须要有一个前台进程,docker 发现没有应用就自动停止了容器
# 例如nginx容器启动后,发现自己没有提供服务就会立即停止
查看容器日志
# 创建一个容器并植入一个shell脚本
[root@pinyoyougou-docker /]# docker run -it centos /bin/sh -c "while true;do echo xiye;sleep 1;done"
# 然后用日志查询命令查看容器日志
[root@pinyoyougou-docker /]# docker logs -tf --tail 10 8c
查看容器内部的进程id
# docker top 容器id
[root@pinyoyougou-docker /]# docker top 8c
UID PID PPID C STIME TTY TIME
root 6434 6414 0 15:18 pts/0 00:00:00
root 6659 6434 0 15:21 pts/0 00:00:00
查看镜像源数据
# docker inspect 8c
[root@pinyoyougou-docker /]# docker inspect 8c
[
{
"Id": "8c3e68bd05e77a1fc2f89c184fc796d1755e9b05973c1c3ff0d6a66c1f9a92ff",
"Created": "2021-04-26T07:18:41.899275562Z",
"Path": "/bin/sh",
"Args": [
"-c",
"while true;do echo xiye;sleep 1;done"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 6434,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-04-26T07:18:42.244231037Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:300e315adb2f96afe5f0b2780b87f28ae95231fe3bdd1e16b9ba606307728f55",
"ResolvConfPath": "/var/lib/docker/containers/8c3e68bd05e77a1fc2f89c184fc796d1755e9b05973c1c3ff0d6a66c1f9a92ff/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/8c3e68bd05e77a1fc2f89c184fc796d1755e9b05973c1c3ff0d6a66c1f9a92ff/hostname",
"HostsPath": "/var/lib/docker/containers/8c3e68bd05e77a1fc2f89c184fc796d1755e9b05973c1c3ff0d6a66c1f9a92ff/hosts",
"LogPath": "/var/lib/docker/containers/8c3e68bd05e77a1fc2f89c184fc796d1755e9b05973c1c3ff0d6a66c1f9a92ff/8c3e68bd05e77a1fc2f89c184fc796d1755e9b05973c1c3ff0d6a66c1f9a92ff-json.log",
"Name": "/exciting_kapitsa",
"RestartCount": 0,
"Driver": "devicemapper",
"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,
"CgroupnsMode": "host",
"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": {
"DeviceId": "93",
"DeviceName": "docker-253:0-674-7bac96387f711f8431ebbcfaf2280105eb5496e05b111f04cb254feac8f77f4e",
"DeviceSize": "10737418240"
},
"Name": "devicemapper"
},
"Mounts": [],
"Config": {
"Hostname": "8c3e68bd05e7",
"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/sh",
"-c",
"while true;do echo xiye;sleep 1;done"
],
"Image": "centos",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20201204",
"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": "889d86bb8d9e49fdee735cc2e3bea300c1ce6de5e1b2eebdc59e93399125b0c1",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/889d86bb8d9e",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "f607c2da6df4ff7fa317f83467acc0a7617ceaeaf909909a05ce697913a3a1e0",
"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": "57dfc8e244c598a843116e956699ee11c32eaac81ebdd1c67c3c6b5439c94df5",
"EndpointID": "f607c2da6df4ff7fa317f83467acc0a7617ceaeaf909909a05ce697913a3a1e0",
"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 /bin/bash
#这个命令是进入这个容器正在运行的命令行
docker attach 容器id
拷贝容器文件到主机上
# docker cp 容器id:容器内路径 外部主机路径
[root@pinyoyougou-docker /]# docker cp 8c3e68bd05e7:/fyx/nihaio.txt /
作业练习
练习1(nginx部署)
Docker 安装Nginx
# 搜索镜像
docker searcg nginx;
# 下载最新镜像;
docker pull nginx;
# -d 后台运行 --name 起名字 -p3352:80 向外主机爆露3352的端口容器内部是80的端口
docker run -d --name nginx1 -p 3352:80 nginx;
#本机发起一个请求
[root@pinyoyougou-docker devicemapper]# curl 127.0.0.1:3352
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# 发现能收到返回的网页数据
练习2(tomcat)
安装一个tomcat
# 直接运行命令如果没有tomcat 默认会下载tomcat
docker run -d -p 8080:8080 tomcat;
# 外网访问发现404 这个原因是因为阿里云镜像会默认下载最小的镜像 导致tomcat是阉割版的 里面的内容一部分是少的
练习3(es+kibana)
安装es
#es 暴漏的端口很多
#es 十分的耗内存
#es 的数据一般需要放置到安全目录 ! 挂载
#--net somenetwork ? 网络配置
#这样运行起来发现占用内存太大所以要加内存限制
docker run -d --name myes -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
#使用-e 来指定docker 的运行时内存占用大小
docker run -d --name myes -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms64m -Xmx512m" -e "discovery.type=single-node" elasticsearch:7.6.2
安装kibana
安装前要思考的问题由于Docker容器之间是相互隔离的kibana改如何链接es?
#答案是可以通过docker 内部网络ip来连接
docker inspect es镜像id
# 然后通过你获取到的ip 更改kibana启动的ip命令 启动成功访问就可以了
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://172.17.0.3:9200 -p 5601:5601 -d kibana:7.4.2
Docker图形化管理工具(Portainer)
#安装
docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
Docker镜像详解
镜像是什么
镜像是一种轻量级.可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软甲,它包含运行某个软件所需的所有内容,包括代码,运行时,库,环境变量和配置文件。所有的应用直接打包docker镜像,直接运行
如何获得镜像
- 从远程仓库下载
- 朋友拷贝给你
- 自己制作一个镜像DockerFile
Docker镜像加载原理
联合文件系统
就类似与Git的提交记录,简单来讲就是有两个镜像如果镜像B有了镜像A的环境,就不需要再进行下载了
commit镜像
docker commit 提交容器成为一个新的副本
# 命令和git原理类似
docker commit -m="描述" -a=“xiye” 容器id 镜像id
实战测试
# 启动一个tomcat 然后把webapss.dist 文件目录放置到webapps可访问
# 运行nginx 镜像
docker run -p 80:8080 -d e1ac7618b15d
# 然后进入正在运行的程序
[root@pinyoyougou-docker devicemapper]# docker exec -it 940b08cf57f2 /bin/bash
root@940b08cf57f2:/usr/local/tomcat#
# 修改内容后然后提交
docker commit -a="xiye" -m="提交的内容" 940b08cf57f2 e1ac7618b15d
# 查看自己的镜像
[root@pinyoyougou-docker devicemapper]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
e1ac7618b15d latest 5f4963f45438 45 docker ago 454MB
容器数据卷
什么是容器数据卷
docker的理念回顾
将应用打包成一个镜像
那应用的数据怎么办?
如果数据都在容器中,那么我们容器删除,数据就会丢失!需求:数据可以持久化
容器之间可以有一个数据共享的技术! Docker容器中产生的数据,同步到本地!
这就是卷技术!目录的挂载,将我们容器内的目录,挂载到Linux上面实现持久化
所以数据卷就是容器的持久化和同步操作
使用数据卷
方式1:直接使用命令来挂载
docker run -it -v 主机目录:容器目录 centos
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X7ahLBFY-1631176874112)(https://i.loli.net/2021/05/07/nH8UB56DIiQWJwO.png)]
**接一下来主机和容器内部就建立了链接 任何操作的目录都会同步类似vue双向绑定 就算容器停止当容器再次启动时 也会去同步主机绑定数据 **
好处:我们以后修改只需要在本地修改,容器内会自动同步!
实战:安装MySQL
思考:mysql数据持久化的问题
# 获取镜像
[root@pinyoyougou-docker ~]# docker pull mysql:5.7
# 运行 参数详解-d后台运行 -p 爆露端口 -v 挂在主机与容器的数据卷和配置文件 -e 指定Mysql密码 --name 指定运行容器名称
docker run -d -p 3301:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysqk/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=fyxzuishuai12 --name fyxmysql mysql:5.7
我们接下来在本地连接mysql创建一个fyxdatabase的表然后删除容器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kG5gtTIT-1631176874113)(https://i.loli.net/2021/05/08/jy4xHVO2hZN1Tlt.png)]
接下来重新运行和上面命令一样的docker 运行命令我们发现数据还是存在的
具名挂载和匿名挂载
# 匿名挂载(不起名字)
-v 容器路径
# 具名挂载(起名字)
-v juming-name:容器路径
# 指定路径挂载
-v /宿主机路径:容器内路径
# 查看所有的卷情况
docker volume ls
DRIVER VOLUME NAME
local 00afc05713216e1df34ebcef8454d67b8072e67ab76353455dbb449650200515
local 75e2cf012dece07504b8c83ea4b55d66fe8c8e8a6de027618bae71d75cb7143d
local 3907c368ad104eec5f5def2a6d9df9d53a06a23b3355aac9a09f7fed0d47e3bd
local a74534db8cc3042061bc2596d366d75907378d4db63fad19d2bf41a3fcb90721
#查看卷的具体挂载路径
[root@pinyoyougou-docker data]# docker volume inspect 00afc05713216e1df34ebcef8454d67b8072e67ab76353455dbb449650200515
[
{
"CreatedAt": "2017-10-24T11:17:26+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/00afc05713216e1df34ebcef8454d67b8072e67ab76353455dbb449650200515/_data",
"Name": "00afc05713216e1df34ebcef8454d67b8072e67ab76353455dbb449650200515",
"Options": null,
"Scope": "local"
}
]
所有docker容器内的卷没有指定本机路径的情况下都是在**/var/lib/docker/volumes/xxxx_data**
我们通过具名挂载可以方便的找到我们的一个卷
不建议使用匿名挂载
拓展
# ro 或者rw 是什么意思
# 通过 -v juming-nginx:/etc/nginx:ro 表示这个文件下的内容是只读 rw 就是可读和可写
docker run -d -P --name ngixnp01 -v juming-nginx:/etc/nginx:ro nginx
初识Dockerfile
Dockerfile就是构建docker镜像的脚本文件!
通过这个脚本可以生成脚本镜像,镜像是一层一层的,脚本是一个个的命令,每个命令就是一层!
[root@pinyoyougou-docker ~]# vim dockerfile1
# 再centos镜像基础之上构建
FROM centos
#挂在卷
VOLUME ["volume01","volume02"]
# 输出
CMD echo "---end-----"
# 默认走这个控制台
CMD /bin/bash
#使用命令构建镜像
[root@pinyoyougou-docker ~]# docker build -f dockerfile1 -t myimages .
#使用查看命令
[root@pinyoyougou-docker dockerdata]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myimages latest e448eb8c6a43 2 minutes ago 209MB
进入容器查看目录发现了两个我们构建docker文件的卷挂载
然后我们使用docker inspect 命令查看数据时会发现镜像默认的在宿主机上面开辟了两个同步卷路径
容器数据卷
实现容器与容器之间的数据共享就是数据卷容器
多个mysql实现数据共享(下面代码可能有问题可以参考网络)
# 创建父容器
docker run -d -p 3301:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysqk/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=fyxzuishuai12 --name fyxmysql mysql:5.7
# 创建子容器去继承父容器的卷挂载
docker run -d -p 3302:3306 -e MYSQL_ROOT_PASSWORD=fyxzuishuai12 --name fyxmysql2 mysql:5.7 --volumes-form fyxmysql
结论:
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止.
但是一旦你持久化到了本地,这个时候,本地数据是不会删除的
DockerFile
Dockerfile介绍
dockerfile是用来构建docker镜像的文件! 就是命令参数脚本!
构建步骤:
- 编写一个dockerfile文件
- docker build 构建成为一个镜像
- docker run 运行镜像
- docker push 发布镜像(dockerhub,阿里云镜像仓库)
DockerFile构建过程
基础知识:
1、每个保留关键字(指令)都是必须大写字母
2、执行从上到下顺序执行
3、# 表示注释
4、每一个指令都会创建提交一个新的镜像层,并提交!
DockerFile:构建文件,定义了一切的步骤,源代码
DockerImages:通过DockerFile构建生成的镜像,最终发布和运行的产品,原来是jar或者是war
Docker容器:容器就是镜像运行起来提供服务
DockerFile的指令
#基础镜像,一切从这里开始
FROM
#镜像是谁写的.姓名+邮箱
MAINTAINER
#镜像构建的时候需要运行的命令
RUN
#给镜像添加类似tomcat的环境
ADD
#镜像的工作目录
WORKDIR
#给容器挂载卷
VOLUME
#保留端口配置
EXPOSE
#指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被代替
CMD
#指定这个容器启动的时候要运行的命令,可以追加命令
ENTRYPOINT
#当构建一个被继承DockerFile这个时候就会运行OnBuild的指令,触发指令
ONBUILD
#将文件拷贝到镜像中
COPY
#构建的时候设置环境变量
ENV
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LWDEAzkH-1631176874117)(https://i.loli.net/2021/05/24/6m4eOzoHF5PlY2v.png)]
实战基础
Docker Hub 中99%镜像都是从FROM Scratch开始的,然后配置需要的软件和配置来进行构建的
创建一个自己的Centos
编写DockerFile文件
# 在centos基础上构建镜像
FROM centos
# 镜像作者信息
MAINTAINER fanyuanxin<1349516890@qq.com>
# 构建环境变量
ENV MYPATH /usr/local
# 镜像的工作目录
WORKDIR $MYPATH
# 镜像构建的时候运行的命令
RUN yum -y install vim
RUN yum -y install net-tools
# 爆露的端口
EXPOSE 8080
CMD echo $MYPATH
CMD echo "---end----"
CMD /bin/bash
构建镜像并运行
# 构建dockerfile
[root@pinyoyougou-docker mydockerfile]# docker build -f mydockerfile-centos -t mycentos:0.1 .
# 运行自己的容器
root@pinyoyougou-docker mydockerfile]# docker run -it mycentos:0.1
[root@442f7693c9c8 local]# pwd
/usr/local
[root@442f7693c9c8 local]# vim dockerfile
# 发现vim 命令已经安装过了
[root@442f7693c9c8 local]# vim --version
VIM - Vi IMproved 8.0 (2016 Sep 12, compiled Jun 18 2020 15:49:08)
CMD命令使用&ENTRYPOINT区别
# 编写dockerfile文件
[root@pinyoyougou-docker ~]# vim dockerfile
FROM centos
# 区别 CMD 和ENTRYPOINT 区别就是docker run CMD构建的镜像不能追加指令而ENTRYPOINT构建的镜像可以追加命令
CMD ["ls","-a" ]
# ENTRYPOINT ["ls","-a" ]
# 构建dockerfile
[root@pinyoyougou-docker ~]# docker build -f dockerfile -t cmdtest .
# 运行docker容器 发现ls命令生效
[root@pinyoyougou-docker ~]# docker run cmdtest
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
实战:Tomcat镜像
1、准备镜像文件,tomcat压缩包,jdk的压缩包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bRA3rS8N-1631176874117)(https://i.loli.net/2021/05/26/qukdrVCnpw7bZzv.png)]
2、编写dockerfile文件
# 基础镜像
FROM centos
# 作者信息
MAINTAINER fanyuanxin<1349516890@qq.com>
# 复制当前我目录下的readme.txt 到/usr/local/目录下
COPY readme.txt /usr/local/readme.txt
# 添加jdk环境
ADD jdk-8.tar.gz /usr/local/
# 添加apache-tomcat目录
ADD apache-tomcat-8.5.66.tar.gz /usr/local/
# 运行的时候安装vim
RUN yum -y install vim
# 配置环境变量
ENV MYPATH /usr/local
# 配置工作目录
WORKDIR $MYPATH
# 配置java环境变量和tomcat环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_171
ENV CLASSPATG $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.66
ENV CATALINA_BASH /usr/local/apache-tomcat-8.5.66
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
# 爆露8080端口
EXPOSE 8080
# 执行tomcat运行命令和显示日志
CMD /usr/local/apache-tomcat-8.5.66/bin/startup.sh && tail -F /usr/local/apache-tomcat-8.5.66/bin/logs/catalina.out
3、构建docker镜像
docker build -t diytocmat .
4、运行tomcat容器
docker run -d -p 9090:8080 -v /usr/local/code/:/usr/local/apache-tomcat-8.5.66/webapps/ -v /usr/local/codelogs/:/usr/local/apache-tomcat-8.5.66/logs/ diytocmat
5、发布代码到/usr/local/code (我这里用tomcat自带的ROOT代码发布进去测试)
发布自己的镜像
DockerHub
1、地址 https://hub.docker.com/ 需要注册自己的账号
2、确定这个账号可以登录
3、在服务器上面提交自己的镜像
docker login -u 自己的账号然后回车输入自己的密码
4、提交自己的镜像
# 首先需要tag 你的镜像生成发布镜像 镜像名格式必须是dockerhub账号id/镜像名:版本号
docker tag 1124195418ad xiye1234/diytomcat:1.0
# 发布镜像
docker push xiye1234/diytomcat:1.0
# 成功后会受到一封邮件点击确定就能最终上传到仓库了
阿里云镜像发布
1、登录阿里云并搜索容器镜像服务
2、进入个人版
3、创建命名空间
4、创建镜像仓库,代码源选择本地仓库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xRqMrbCb-1631176874119)(https://i.loli.net/2021/05/31/q4OxEK96fwTLgzG.png)]
5、点击自己创建的仓库名里面有详细的发布镜像教程
可以在镜像版本的地方查看自己发布的镜像
小结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sxeX0Vax-1631176874121)(https://i.loli.net/2021/05/31/8ZgofT5mM1IOGJp.png)]
Docker网络
理解Docker0
- ip addr查看本机网卡
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jwfFukVp-1631176874121)(https://i.loli.net/2021/05/31/zLpi8IsugtmqP3U.png)]
发现有三个网络 docker0网络是安装docker自动安装的
问题: docker 是如何处理容器网络访问的?
# 准备一个docker 容器
docker run -d -P --name tomcat01 tomcat
# 查看容器ip地址
[root@pinyoyougou-docker usr]# docker exec -it dcdbb51e1cf7 ip addr
# 容器本机回环
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
# 这个容器网络地址是docker 分配
56: eth0@if57: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global
# ping 容器ip发现可以ping通
[root@pinyoyougou-docker usr]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.183 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.044 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.041 ms
当我们运行过一个容器后再使用ip addr时 会发现又多了一个网络会发现@后面的网络名和容器内部网络名相似
# 这个就是使用的evth-pair技术 就是一对的虚拟设备接口,他门都是称对出现的,一段连着协议,一段彼此相连
# 正因为有这个特性,evth-pair 充当一个桥梁,连接各种虚拟网络设备
# 我们再启动一个tomcat2
docker run -d -P --name tomcat02 tomcat
# 然后ping tomcat1 发现是可以ping 通的
[root@pinyoyougou-docker usr]# docker exec -it tomcat02 ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.199 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.045 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.043 ms
# 然后我们发现容器和容器是可以ping通的
# 小知识点 可以使用 arp -a 命令查看
结论:docker0就相当于是个交换机的角色 容器容器相互访问都是先通信到docker0解析到要的具体容器内部
docker容器中所有的网络接口都是虚拟的,虚拟转发效率高只要容器删除,对应网桥一对就没有了
–link
思考一个场景,我们编写了一个微服务,databaseurl=ip:项目不重启,数据库ip换掉了,我们希望可以处理这个问题可以通过名字来访问容器
# 我们先启动两个tomcat01 和tomcat 02
[root@pinyoyougou-docker ~]# docker run -d -P --name tomcat01 tomcat
[root@pinyoyougou-docker ~]# docker run -d -P --name tomcat02 tomcat
# 然后我们通过容器名ping tomcat网络 发现并不能通过容器名ping通
[root@pinyoyougou-docker ~]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: No address associated with hostname
# 当我们通过--link指定容器名 发现tomcat03 可以通过ping同 但是link是单向的 tomcat02 ping不同tomcat03
[root@pinyoyougou-docker ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
[root@pinyoyougou-docker ~]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.096 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.062 ms
# 为什么ping 查看tomcat03的hosts
[root@pinyoyougou-docker ~]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 tomcat02 a922370e128d
172.17.0.4 559b325edc65
本质探究:–link就是在我们hosts配置中增加了一个与tomcat02的ip映射
我们现在玩Docker已经不建议使用–link 因为–link不是双向的
我们可以使用自定义网络,不使用docker0!
自定义网络
解决–link 不能双向访问的问题
查看docker的所有网络
[root@pinyoyougou-docker ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
eb50498883b1 bridge bridge local
c2b8cb191da4 host host local
d11777ea36d7 none null local
网络模式
bridge :桥接模式 docker(默认)
none : 不配置网络
host : 和宿主机共享网络
container :容器网络连接(局限性很大不推荐使用)
测试
# 我们直接启动的命令 不指定--net 就默认使用的是--net bridge 桥接模式 就是我们的docker0
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat
# docker0特点: 域名不能访问,--link可以打通连接!但是只是单向的极为不方便
# 所以我们可以自定义一个网络
[root@pinyoyougou-docker ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
3de228bd7998a41ef4d1537386f07c8959f521eb6e2738476a750bca6012cf27
[root@pinyoyougou-docker ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
eb50498883b1 bridge bridge local
c2b8cb191da4 host host local
3de228bd7998 mynet bridge local
d11777ea36d7 none null local
# 使用我们自己创建的网络运行容器 发现我们自定义的网络可以直接通过容器名ping通
[root@pinyoyougou-docker ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
[root@pinyoyougou-docker ~]# docker run -d -P --name tomcat01-mynet --net mynet tomcat
[root@pinyoyougou-docker ~]# docker run -d -P --name tomcat02-mynet --net mynet tomcat
[root@pinyoyougou-docker ~]# docker exec -it tomcat01-mynet ping tomcat02-mynet
PING tomcat02-mynet (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat02-mynet.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.077 ms
64 bytes from tomcat02-mynet.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.063 ms
结论、我们自定义的网络docker都已经帮我们维护好了应对的关系,推荐我们平时这样使用网络
网络连通
解决不处于同一个网络下如何实现容器连接到不同的网络的容器
Docker network connect
# 先创建一个桥接模式的tomcat
[root@pinyoyougou-docker ~]# docker run -d -P --name tomcat01-bridge tomcat
# 发现ping不通
docker exec -it tomcat01-bridge ping tomcat02-mynet
ping: tomcat02-mynet: No address associated with hostname
# 使用docker network connect 网络名 荣启铭
docker network connect mynet tomcat01-bridge
# 之后发现不处于同一个网络下也是可以正常使用的
docker exec -it tomcat01-bridge ping tomcat02-mynet
PING tomcat02-mynet (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat02-mynet.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.088 ms
64 bytes from tomcat02-mynet.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.062 ms
结论:假设要跨网络操作别人,就需要使用docker network connect 连通!