Docker
需要原笔记请+v
笔记整理不易!!!请点一个关注!!!
Docker概述
Docker为什么出现?
一款产品:开发--上线 两套环境!应用环境,应用配置!
环境配置十分的麻烦:每个机器都需要部署环境(集群Redis、ES、Hadoop....),不能跨平台
发布一个项目jar+(Redis Mysql jdk ES),项目能不能带上环境安装打包
传统:开发 jar 运维来做
现在:开发打包部署上线,一套流程做完!
java -- apk -- 发布(应用商店) ----张三使用apk ---安装即可用
java -- jar (环境)---- 打包项目带上环境(镜像) ----(Docker仓库:商店)---下载我们发布的镜像---直接运行即可
解决方案!
Docker的设计思想来自于集装箱!
Jre ---多个应用运行(可能产生端口冲突)--- 出现交叉(存在使用一套环境,需要隔离出来)
隔离:Docker核心思想!打包装箱!每个箱子(容器)都是相互隔离的!
Docker为什么火?十分的轻巧!
在容器技术出来之前,我们都是使用的虚拟机技术
虚拟机:在window中安装一个Vmware,通过vm我们可以虚拟出来一台或者多台电脑!笨重(size大,只需要命令)!
虚拟机属于虚拟化技术,Docker容器技术,也是一种虚拟化技术!
vm:linux centos原生镜像(说白了就是一台电脑!) 隔离:就需要开启多个虚拟机!就会非常的笨重 docker:隔离,镜像(镜像机制,最核心的环境(命令+开机启动 最小4m就欧克了)+jdk+mysql)十分的小巧,运行镜像就可以了!
Docker能干哈
之前的虚拟化技术
虚拟机技术:
1.资源占用非常大
2.冗余步骤太多
3.启动慢
容器技术
==容器化技术不是模拟的一个完整的操作系统==
比较虚拟机技术和Docker的不同:
-
传统的虚拟机:虚拟出一套硬件,运行完整的的操作系统,然后在这个系统上安装和运行软件
-
容器内的应用是直接运行在宿主机的内核,容器是没有自己的内核的,也没有虚拟硬件,所以轻便
-
每个容器之间是相互隔离的,每个容器都有属于自己的一套文件系统(lib),互不影响。
Docker的基本组成
镜像(images):
docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,tomcat镜像===>run===>tomcat01容器(提供服务器),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)。
容器(container):
Docker利用容器技术,独立运行一个或者一组应用,通过镜像来创建的。
启动,停止,删除,基本命令!
暂时可以将这个容器理解一个简易的Linux系统。
仓库(registry):
仓库用来存放镜像的地方
容器服务器
Docker安装
Docker官网地址:Install Docker Engine on CentOS | Docker Docs
回顾HelloWorld流程
底层原理
Docker是怎么工作的?
Docker是一个Client - Server结构的系统,Docker的守护进程运行在主机上,通过Socket从客户端访问!
DockerServer接收到Docker-Client的指令,就会执行这个命令!
Docker为什么会比vm块?
1.Docker有着比虚拟机更少的抽象层。
2.docker利用的是宿主机的内核,虚拟机需要Guest OS
所以说,新建一个容器的时候,docker是不需要像虚拟机那样重新加载一个操作系统的内核,而docker是利用宿主机的操作系统
Docker的常用命令
docker version #显示docker的版本信息
docker info #显示更加详细的信息,包括镜像和容器的数量
docker 命令 --help
帮助文档:Reference documentation | Docker Docs
镜像命令
docker images 查看所有本地的主机上的镜像
[root@localhost /]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest d2c94e258dcb 8 months ago 13.3kB mysql 8.0 3218b38490ce 2 years ago 516MB #解释 REPOSITORY 镜像对的仓库源 TAG 镜像的版本 IMAGE ID 镜像的id CREATED 镜像的创建时间 SIZE 镜像大小 #可选项 -a, --all Show all images (default hides intermediate images) -q, --quiet Only show image IDs
docker search 搜索镜像
[root@localhost /]# docker search mysql NAME DESCRIPTION STARS OFFICIAL AUTOMATED mysql MySQL is a widely used, open-source relation… 14762 [OK] mariadb MariaDB Server is a high performing open sou… 5632 [OK] percona Percona Server is a fork of the MySQL relati… 623 [OK] phpmyadmin phpMyAdmin - A web interface for MySQL and M… 927 [OK] bitnami/mysql Bitnami MySQL Docker Image 104 [OK] #可选项 ,通过搜索来过滤 --filter=STARS=3000
docker pull 下载镜像
# 下载镜像 docker pull 镜像名[;tag] [root@localhost /]# docker pull mysql:5.7 #如果不写tag,就默认就是latest 5.7: Pulling from library/mysql 72a69066d2fe: Already exists #分层下载,docker images的核心 联名文件系统 93619dbc5b36: Already exists 99da31dd6142: Already exists 626033c43d70: Already exists 37d5d7efb64e: Already exists ac563158d721: Already exists d2ba16033dad: Already exists 0ceb82207cd7: Pull complete 37f2405cae96: Pull complete e2482e017e53: Pull complete 70deed891d42: Pull complete Digest: sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94 #签名 Status: Downloaded newer image for mysql:5.7 docker.io/library/mysql:5.7 #真实地址 #等价于 docker pull mysql docker pull docker.io/library/mysql:5.7
docker rmi 删除镜像
[root@localhost /]# docker rmi -f 容器id #删除指定的容器 [root@localhost /]# docker rmi -f 容器id 容器id 容器id 容器id #删除多个容器 [root@localhost /]# docker rmi -f $(docker images -aq) #删除全部的容器
容器命令
说明:我们有了镜像才可以创建容器,linux,下载centos镜像来测试
docker pull centos
新建容器并重启
docker run [可选参数] image # 参数说明 --name="Name" 容器名字 tomcat01 tomcat02 ,区分容器 -d 后台方式运行, -it 使用交互方式进行,进入容器查看内容 -p 指定容器的端口, -p -p 主机端口:容器端口 -p 容器端口 -P 随机指定端口 #测试 启动并进入容器 [root@localhost /]# docker run -it centos /bin/bash [root@74c7fb4e0c58 /]# ls #查看容器内的centos,基础版本 很多命令都不完善 bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
列出所有的运行的容器
# docker ps 命令 # 列出当前正在运行的额容器 -a # 列出当前正在运行的额容器+历史运行的容器 -n=? #显示最近创建的容器 -q #只显示容器的编号 [root@localhost /]# clear [root@localhost /]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@localhost /]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 74c7fb4e0c58 centos "/bin/bash" 5 minutes ago Exited (127) 17 seconds ago inspiring_margulis 13cfdf19b3d0 centos "/bin/bash" 6 minutes ago Exited (0) 5 minutes ago gallant_almeida 81dd0cf1175a hello-world "/hello" 7 hours ago Exited (0) 7 hours ago nifty_lumiere [root@localhost /]#
退出容器
exit #直接退出 ctrl +P+Q #容器不停止退出
删除容器
docker rm 容器 id #删除指定容器,但是不能删除正在运行的容器 docker rm -f $(docker images -aq) #删除所有容器 docker ps -a -q|xargs docker rm #删除所有容器
启动和停止容器的操作
docker start 容器id #启动容器 docker restart 容器id #重启容器 docker stop 容器id #停止当前正在运行的容器 docker kill 容器id #强制停止当前d
常用其他命令
后台启动容器
# 命令 docker run -d 镜像名 后台启动容器 [root@localhost ~]# docker run -d centos # 命令 docker ps 查看当前运动的容器 [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@localhost ~]# # 结果发现启动的容器自己停掉了 # 常见的坑, docker容器使用后台进行运行,就必须要有一个前台进程,docker发现没有应用,就会自动停止 # 常见的就是nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了
查看日志
docker logs -f -t (-tf) --tail [number] 容器,没有日志 #自己编写一段shell脚本 [root@localhost ~]# docker run -d centos /bin/sh -c "while true;do echo shuaishuai;sleep 1;done" 94d5f15e1e8ab0f795e5dc7566d3253f42dc4405b09759328b3bb6ad99e0066a #[root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 94d5f15e1e8a centos "/bin/sh -c 'while t…" 8 seconds ago Up 6 seconds lucid_ellis [root@localhost ~]# #显示日志 -tf #显示全部日志 --tail number #显示number行的日志条数 [root@localhost ~]# docker logs -t -f --tail 10 94d5f15e1e8a 2024-01-15T08:51:27.429680791Z shuaishuai 2024-01-15T08:51:28.434074216Z shuaishuai 2024-01-15T08:51:29.437888854Z shuaishuai 2024-01-15T08:51:30.441702052Z shuaishuai 2024-01-15T08:51:31.446325407Z shuaishuai 2024-01-15T08:51:32.449788976Z shuaishuai
查看容器中的进程信息
# 命令 docker top 容器ID [root@localhost ~]# docker top 94d5f15e1e8a UID PID PPID C STIME TTY root 1819 1797 0 16:46 ? root 2599 1819 0 16:57 ?
查看镜像的元数据(信息)
# 命令 docker inspect 容器id [root@localhost ~]# docker inspect 94d5f15e1e8a [ { "Id": "94d5f15e1e8ab0f795e5dc7566d3253f42dc4405b09759328b3bb6ad99e0066a", "Created": "2024-01-15T08:46:43.862841772Z", "Path": "/bin/sh", "Args": [ "-c", "while true;do echo shuaishuai;sleep 1;done" ], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 1819, "ExitCode": 0, "Error": "", "StartedAt": "2024-01-15T08:46:44.251924785Z", "FinishedAt": "0001-01-01T00:00:00Z" }, "Image": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6", "ResolvConfPath": "/var/lib/docker/containers/94d5f15e1e8ab0f795e5dc7566d3253f42dc4405b09759328b3bb6ad99e0066a/resolv.conf", "HostnamePath": "/var/lib/docker/containers/94d5f15e1e8ab0f795e5dc7566d3253f42dc4405b09759328b3bb6ad99e0066a/hostname", "HostsPath": "/var/lib/docker/containers/94d5f15e1e8ab0f795e5dc7566d3253f42dc4405b09759328b3bb6ad99e0066a/hosts", "LogPath": "/var/lib/docker/containers/94d5f15e1e8ab0f795e5dc7566d3253f42dc4405b09759328b3bb6ad99e0066a/94d5f15e1e8ab0f795e5dc7566d3253f42dc4405b09759328b3bb6ad99e0066a-json.log", "Name": "/lucid_ellis", "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, "ConsoleSize": [ 28, 113 ], "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", "Isolation": "", "CpuShares": 0, "Memory": 0, "NanoCpus": 0, "CgroupParent": "", "BlkioWeight": 0, "BlkioWeightDevice": [], "BlkioDeviceReadBps": [], "BlkioDeviceWriteBps": [], "BlkioDeviceReadIOps": [], "BlkioDeviceWriteIOps": [], "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpusetCpus": "", "CpusetMems": "", "Devices": [], "DeviceCgroupRules": null, "DeviceRequests": null, "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", "/sys/devices/virtual/powercap" ], "ReadonlyPaths": [ "/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger" ] }, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/6cd51c92e596ae99038869930b47f219139b396b66df04bc8128a0c76c22ef06-init/diff:/var/lib/docker/overlay2/f8b02d3e2722c231dc13e2ccba1d3f33f1ab8dd826162a567ecb989cf54dd81b/diff", "MergedDir": "/var/lib/docker/overlay2/6cd51c92e596ae99038869930b47f219139b396b66df04bc8128a0c76c22ef06/merged", "UpperDir": "/var/lib/docker/overlay2/6cd51c92e596ae99038869930b47f219139b396b66df04bc8128a0c76c22ef06/diff", "WorkDir": "/var/lib/docker/overlay2/6cd51c92e596ae99038869930b47f219139b396b66df04bc8128a0c76c22ef06/work" }, "Name": "overlay2" }, "Mounts": [], "Config": { "Hostname": "94d5f15e1e8a", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/bin/sh", "-c", "while true;do echo shuaishuai;sleep 1;done" ], "Image": "centos", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": { "org.label-schema.build-date": "20210915", "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": "da9bf0a283f8df77bf35b9cd4c519bfb2d2aab04a6943d2c01fe89857135cb3f", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": {}, "SandboxKey": "/var/run/docker/netns/da9bf0a283f8", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "be3754dd66295e82ca8478a22a0581b11760468a035ffe22cb13bfff657c1c74", "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": "687b45745406a56cca49f7c7f5c3251931456b8b4a218dfb092d76b35005388f", "EndpointID": "be3754dd66295e82ca8478a22a0581b11760468a035ffe22cb13bfff657c1c74", "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 # 测试 [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 94d5f15e1e8a centos "/bin/sh -c 'while t…" 6 hours ago Up 6 hours lucid_ellis [root@localhost ~]# docker exec -it 94d5f15e1e8a /bin/bash [root@94d5f15e1e8a /]# ls bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var [root@94d5f15e1e8a /]# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 11:49 ? 00:00:06 /bin/sh -c while true;do echo shuaishuai;sleep 1;done root 10842 0 0 14:51 pts/0 00:00:00 /bin/bash root 10875 1 0 14:51 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/slee root 10876 10842 0 14:51 pts/0 00:00:00 ps -ef # 第二种方式 #命令 docker attach 容器id #测试 [root@localhost ~]# docker attach 94d5f15e1e8a 正在执行当前的代码... # docker exec # 进入容器后开启一个新的终端,可以在里面操作(常用) # docker attach # 进入容器正在执行的终端,不会启动新的进程
从容器内拷贝文件到主机上
docker cp 容器id:容器的内存 目的主机的路径 #查看当前主机下的home目录 [root@localhost home]# ls lc wang wangwu zhangsan #查看运行容器 [root@localhost home]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 57734f502879 mysql:8.0 "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 3306/tcp, 33060/tcp serene_clarke #进入docker容器内部 [root@localhost home]# docker attach 57734f502879 root@57734f502879:/# ls bin dev entrypoint.sh home lib64 mnt proc run srv tmp var boot docker-entrypoint-initdb.d etc lib media opt root sbin sys usr #在home目录下创建text.java文件 root@57734f502879:/# cd /home root@57734f502879:/home# touch text.java root@57734f502879:/home# exit exit [root@localhost home]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@localhost home]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 57734f502879 mysql:8.0 "docker-entrypoint.s…" 6 minutes ago Exited (0) 19 seconds ago serene_clarke 94d5f15e1e8a centos "/bin/sh -c 'while t…" 7 hours ago Exited (137) 9 minutes ago lucid_ellis #将文件拷贝到主机上 Copy files/folders between a container and the local filesystem [root@localhost home]# docker cp 57734f502879:/home/text.java /home Successfully copied 1.54kB to /home [root@localhost home]# ls lc text.java wang wangwu zhangsan #拷贝是一个手动的过程,未来我们使用-v 卷的技术,可以实现
小结
作业练习
docker 安装 Nginx
# 1.搜索镜像 search 在docker hub查看 # 2.下载镜像 pull # 查看镜像 [root@localhost home]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest d2c94e258dcb 8 months ago 13.3kB nginx latest 605c77e624dd 2 years ago 141MB mysql 5.7 c20987f18b13 2 years ago 448MB mysql 8.0 3218b38490ce 2 years ago 516MB centos latest 5d0da3dc9764 2 years ago 231MB # -d 后台运行 # --name 给容器命名 # -p 宿主机端口:容器内部端口 [root@localhost home]# docker run -d --name nginx01 -p 3344:80 nginx 46f2153709f3cb97e1dda840ac4b37de277c642332d3a447fccb0fea1aebd053 [root@localhost home]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 46f2153709f3 nginx "/docker-entrypoint.…" 11 seconds ago Up 9 seconds 0.0.0.0:3344->80/tcp, :::3344->80/tcp nginx01 [root@localhost home]# curl localhost:3344 # 进入容器 [root@localhost home]# docker exec -it nginx01 /bin/bash # 查看nginx的配置文件 root@46f2153709f3:/# whereis nginx nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx root@46f2153709f3:/# cd /etc/nginx/ root@46f2153709f3:/etc/nginx# ls conf.d fastcgi_params mime.types modules nginx.conf scgi_params uwsgi_params root@46f2153709f3:/etc/nginx#
端口暴露的概念
思考问题:当我们需要多次去修改nginx的配置文件时,都需要进入容器的内部,这是十分繁琐的,我们要是能在容器外部提供一个映射路径,达到在容器外部修改文件名,容器内部就可以自动修改? v 数据卷
docker 安装 tomcat
# 官方的使用 docker run -it --rm tomcat # 我们之前的启动都是后台,停止容器后,容器还是可以查到,docker run -it --rm tomcat一般用于测试,用完就删除 # 下载并启动 # 进入容器 [root@localhost home]# docker exec -it tomcat01 /bin/bash root@b0933e526226:/usr/local/tomcat# #问题:1.linux命令变少了 2.没有webapps 原因:阿里云 镜像的原因。 默认为最小的镜像(tomcat环境),所以不必要的都被剔除掉了 #保证最小可运行环境
docker 安装 elasticsearch
# es 暴露的端口较多 # es 十分的耗内存 # es 的数据一般需要存在放在安全目录!挂载 # --net somenetwork 网络配置 # 启动 elasticsearch docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:tag # 当内核较小时,会存在启动了Linux就卡住了 利用docker stats 查看cpu 内存状态 #测试 [root@localhost home]# curl localhost:9200 { "name" : "5accdaaf17cf", "cluster_name" : "docker-cluster", "cluster_uuid" : "lg8Dq4ufQnmFzwwgEblbeA", "version" : { "number" : "7.6.2", "build_flavor" : "default", "build_type" : "docker", "build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f", "build_date" : "2020-03-26T06:34:37.794943Z", "build_snapshot" : false, "lucene_version" : "8.4.0", "minimum_wire_compatibility_version" : "6.8.0", "minimum_index_compatibility_version" : "6.0.0-beta1" }, "tagline" : "You Know, for Search" } # es 十分耗内存 解决内存限制
# 限制内存 docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="Xms64m -Xmx512m" elasticsearch:tag
Docker镜像
commit镜像
docker commit 提交容器成为一个新的副本(镜像) # 命令 和git原理相似 docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[tag]
测试
# 1.启动一个默认的tomcat # 2.发现默认的tomcat,没有wepapps应用, 镜像原因 # 3.自己拷贝进去 # 4.将我们操作过的容器通过commit提交一个镜像!我们以后用我们修改过后的镜像即可,这就是我我们自己修改过后一个镜像
容器数据卷
什么是容器数据卷
docker的理念回顾
将应用和环境打包成一个镜像!
数据?如果数据都在容器中,那么我们容器删除,数据就会丢失! 需求:数据可以持久化
MySQL,容器删了,删库跑路! 需求:MySQL数据可以存储在本地!
容器之间可以有一个数据共享的技术! Docker容器中产生的数据,同步到本地!
这就是卷技术!目录的挂载,将我们的容器的目录,挂载到linux上面!
挂载
总结:容器的持久化和同步操作!容器间也是可以进行数据共享的!
方式一:使用命令来挂载 -v
docker run -it -v 主机目录:容器内目录 # 测试 [root@localhost ~]# docker run -it -v /home/ceshi:/home centos /bin/bash # 挂载并启动后可以通过 docker inspect 容器id
测试文件的同步
再来测试!
1、停止容器
2、在宿主机上修改文件
3、 启动之前的容器
4、容器内的数据依旧是同步的
好处:我们以后修改只需要在本地修改就可,容器内会自动同步!
实战:安装MySQL
思考:MySQL的持久化的问题!
# 获取镜像 docker pull mysql # 运行容器,需要做数据挂载! #安装mysql,需要配置密码,这是注意点! # 官方测试 docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag # 启动成功之后,我们在本地使用DataGrip来连接测试一下 # DataGrip--连接到服务器的3310---3310和容器内的3306进行映射,这个时候我们就可以连接上了! # 在本地测试创建一个数据库,查看映射路径是否ok!
假设我们将容器删除
发现,我们挂载到本地的数据卷依旧没有丢失,这就是容器数据持久化功能!
具名和匿名挂载
# 匿名挂载 -v 容器内路径 docker run -d -P -v /etc/nginx nginx # 查看所有 volume 的情况 [root@localhost data]# docker volume ls DRIVER VOLUME NAME local 079a9dca99634eab7083a1587f9c009ed90b897bfd683334b8e52d727dca59d9 # 这里发现,这种就是匿名挂载,我们在 -v只写了容器内的路径,没有写容器外的路径! # 具名挂载 [root@localhost data]# docker run -d -P --name nginx02 -v junming-nginx:/etc/nginx nginx abc56d174fe5bcf2c5c8cf222bd5ea0b8273e7aa6bb62246b4c745a6889cdfb9 [root@localhost data]# docker volume ls DRIVER VOLUME NAME local junming-nginx # -v 卷名:容器内路径 # 查看一下这个卷 docker volume inspect 卷名
所用docker容器内的卷,在没有指定特定容器的情况下都是在 /var/lib/docker/volumes/xxxxx/_data
我们通过具名挂载 可以方便的找到我们的一个卷,大多数情况在使用具名挂载
# 如何确定是具名挂载还是匿名挂载,还是指定路径挂载 -v 容器内路径 # 匿名挂载 -v 卷名:容器内路径 # 具名挂载 -v /宿主机路径:容器内路径 #指定路径挂载
拓展:
# 通过 -v 容器内路径:ro rw 改变读写权限 ro readonly # 只读 rw readwrite #读写 # 一旦有了这个设置了容器权限,容器对我们挂载出来的内容就有了限定了! docker run -d -P --name nginx02 -v junming-nginx:/etc/nginx:ro nginx docker run -d -P --name nginx02 -v junming-nginx:/etc/nginx:rw nginx # ro 只要看到ro就说明这个路径就只能通过宿主机来操作,容器内部是无法操作的!
初识Dockerfile
Dockerfile就是用来构建docker image 的构建文件!命令脚本!
通过脚本可以生成镜像,镜像是一层一层,脚本一个个的命令,每个命令是一层!
# 创建一个dockerfile文件,名字可以随便取,建议使用dockerfile # 文件中的内容 指令[大写] 参数 FROM centos VOLUME ["volume01","volume02"] CMD echo "----end----" CMD /bin/bash # 这里的每一个命令,就是镜像的一层
# 启动我们自己写的容器
这个卷和容器外部一定有一个同步目录!
查看一下卷挂载的路径
测试一下刚才的文件是否同步出去了!
这种方式我们未来使用十分的多,因为我们通常会自己构建自己的镜像!
假设构建镜像 没有挂载卷,要手动进行挂载 -v 卷名:容器内部路径!
数据卷容器
多个mysql同步数据!
# 同步多个容器,通过我们刚刚自己写的镜像启动
# 测试,当删除docker01,查看一下docker02和docker03是否可以访问这个文件 # 测试结果依旧可以访问
多个mysql实现数据共享
结论
容器之间的配置信息的传递,数据卷容器的生命周期一直持续到没有容器为止!
但是一旦你持久化到本地,这个时候,数据也不会删除的!
DockerFile
DokcerFile介绍
dockerfile使用来构建镜像的文件!命令参数脚本!
构建步骤:
1、编写一个dockerfile文件
2、docker build 构建成为一个镜像
3、docker run 运行镜像
4、docker push 发布镜像(DockerHub 、阿里云镜像仓库)
查看官方如何做的?
很多官方镜像包都是基础包,很多功能都没有,我们通常会自己搭建自己的镜像!
官方既然可以制作镜像,那我们也可以!
DockerFile构建过程
基础知识:
1、每个保留关键字(指令)都必须是大写字母
2、执行从上到下顺序执行
3、#表示注释
4、每个指令都会创建提交一个新的 镜像层,并提交!
dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件是非常简单的!
Docker镜像逐渐成为企业交付的标准,就必须掌握!
步骤:开发、部署、运维 缺一不可!
DockerFile:构建文件,定义了一切的步骤,源代码
DockerImages:通过DockerFile构建生成的镜像,最终发布和运行的产品
Docker容器:容器就是镜像运行起来提供的服务器
Dockerfile的指令
FROM # 指定基础镜像,一起从这里开始构建 MAINTAINER # 镜像是谁写的,姓名+邮箱 RUN # 镜像构建的时候需要运行的命令 ADD # 步骤:tomcat镜像,添加tomcat压缩包!添加内容! WORKDIR # 镜像的工作目录 VOLUME # 挂载的目录 EXPOSE # 保留端口配置 CMD # 指定这个容器启动的需要运行的命令,只有最后一个会生效,可被替代 ENTRYPOINT # 指定这个容器启动的需要运行的命令,可以追加命令 ONBUILD # 当构建一个被继承 DockerFile 这个时候会运行ONBUILD的指令。触发指令 COPY # 将我们的文件拷贝到镜像中 ENV # 构建的时候设置环境变量
实战:构建一个自己的文件
Docker Hub中99%的镜像都是从这个基础镜像过来的FROM scratch,然后配置软件和配置来进行构建
构建一个自己的centos
# 编写一个自己的dockerfile文件 [root@localhost dockerfile]# cat mydockerfile-centos FROM centos MAINTAINER shuaishuai<2549615161@qq.com> ENV MYPATH /usr/local WORKDIR $MYPATH RUN yum -y install vim RUN yum -y install net-tools EXPOSE 80 CMD echo $MYPATH CMD echo "----end----" CMD /bin/bash [root@localhost dockerfile]# # 通过这个文件来构建一个镜像 # 命令 docker build -f dockerfile路径 -t 镜像名:[tag] . [root@localhost dockerfile]# docker build -f mydockerfile-centos -t mycentos:0.1 . # 测试运行
对比:之前的原生的centos
我们增强之后的镜像
我们可以列出本地进行的变更历史
平时我们拿到一个镜像就可以通过history来进行查看它是怎么做的了?
CMD和ENTPYPOINT的区别
CMD # 指定这个容器启动的需要运行的命令,只有最后一个会生效,可被替代 ENTRYPOINT # 指定这个容器启动的需要运行的命令,可以追加命令
测试CMD
# 编写我们的dockerfile文件 FROM centos CMD ["ls","-a"] # 创建一个新的镜像 [root@localhost dockerfile]# docker build -f mydockerfile-cmd-centos -t centos-cmd . [+] Building 0.1s (5/5) FINISHED # 运行容器 [root@localhost dockerfile]# docker run -it centos-cmd . .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 -it centos-cmd -l docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-l": executable file not found in $PATH: unknown. ERRO[0000] error waiting for container: # cmd的情况下, -l 替换了["ls","-a"] 命令,-l不是命令所以会报错!
测试ENTRYPOINT
# 编写dockerfile文件 [root@localhost dockerfile]# vim dockerfile-entrypoint-centos FROM centos ENTRYPOINT ["ls","-a"] [root@localhost dockerfile]# docker build -f dockerfile-entrypoint-centos -t entrypoint . [root@localhost dockerfile]# docker run -it entrypoint . .dockerenv dev home lib64 media opt root sbin sys usr .. bin etc lib lost+found mnt proc run srv tmp var # 我们的追加命令是直接追加到我们的ENTRYPOINT命令后面! [root@localhost dockerfile]# docker run -it entrypoint -l total 0 drwxr-xr-x. 1 root root 6 Jan 17 18:49 . drwxr-xr-x. 1 root root 6 Jan 17 18:49 .. -rwxr-xr-x. 1 root root 0 Jan 17 18:49 .dockerenv lrwxrwxrwx. 1 root root 7 Nov 3 2020 bin -> usr/bin drwxr-xr-x. 5 root root 360 Jan 17 18:49 dev drwxr-xr-x. 1 root root 66 Jan 17 18:49 etc drwxr-xr-x. 2 root root 6 Nov 3 2020 home lrwxrwxrwx. 1 root root 7 Nov 3 2020 lib -> usr/lib lrwxrwxrwx. 1 root root 9 Nov 3 2020 lib64 -> usr/lib64 drwx------. 2 root root 6 Sep 15 2021 lost+found drwxr-xr-x. 2 root root 6 Nov 3 2020 media drwxr-xr-x. 2 root root 6 Nov 3 2020 mnt drwxr-xr-x. 2 root root 6 Nov 3 2020 opt dr-xr-xr-x. 163 root root 0 Jan 17 18:49 proc dr-xr-x---. 2 root root 162 Sep 15 2021 root drwxr-xr-x. 11 root root 163 Sep 15 2021 run lrwxrwxrwx. 1 root root 8 Nov 3 2020 sbin -> usr/sbin drwxr-xr-x. 2 root root 6 Nov 3 2020 srv dr-xr-xr-x. 13 root root 0 Jan 16 15:43 sys drwxrwxrwt. 7 root root 171 Sep 15 2021 tmp drwxr-xr-x. 12 root root 144 Sep 15 2021 usr
Dockerfile当中有很多命令都是十分相似的,我们需要了解他们的区别,我们可以通过对比他们然后测试效果!
实战:创建一个tomcat镜像
1、准备镜像文件,tomcat压缩文件,jdk压缩文件
2、编写Dockerfile文件,官方命名Dockerfile,build的时候会自动寻找这个文件,就不需要-f 指定了
FROM centos MAINTAINER shuaishuai<2549615161@qq.com> COPY readme.txt /usr/local/read.txt ADD jdk-8u401-linux-x64.tar.gz /usr/local/ ADD apache-tomcat-9.0.22.tar.gz /usr/lcal/ RUN yum -y install vim ENV MYPATH /usr/local WORKDIR $MYPATH ENV JAVA_HOME /usr/local/jdk1.8.0_401 ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.22 ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.22 ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA/bin:$CATALINA/lib EXPOSE 8080 CMD /usr/local/apache-tomcat-9.0.22/bin/startup && tail -F /usr/local/apache-tomcat-9.0.22/bin/logs/catalina.out
3、构建镜像
# docker build -t diytomcat .
4、启动镜像
5、访问测试
6、发布项目(因为做了卷挂载,我们直接在本地编写项目就可以发布了!)
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> </web-app>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Welcome to My Web App</title> </head> <body> <h1>Hello, welcome to my web app!</h1> <p>This is a simple JSP page running on Apache Tomcat.</p> <% // 获取当前时间 java.util.Date currentDate = new java.util.Date(); String formattedDate = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(currentDate); %> <p>Current Server Time: <%= formattedDate %></p> </body> </html>
发现:项目部署成功以后,就可以直接访问ok!
我们以后的开发步骤:需要掌握dokcerfile的编写!我们之后的一切都是都是使用容器来运行发布!
发布自己的镜像
DockerHub
提交时也是按照层级来进行提交的
阿里云镜像服务上
1、登陆阿里云
2、找到容器镜像服务
3、创建命令空间
4、创建镜像仓库
5、浏览阿里云
小结
Docker网络
理解Docker0
清空所有环境
测试
三个网络(代表了三个环境)
# docker 是如何处理容器网络访问的?
# docker run -d -P --name tomcat02 tomcat # 查看容器内部的网络地址 ip addr, 发现容器启动的时候会得到一个 eth0@if57 IP地址,docker分配的! [root@localhost tomcat]# docker exec -it tomcat02 ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 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 56: eth0@if57: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever #思考:linux能不能ping通容器内部! [root@localhost tomcat]# ping 172.17.0.3 PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data. 64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.070 ms 64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.065 ms 64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.076 ms # 结论:linux能ping通容器 属于同一网段
原理
1、我们每启动一个docker容器,docker就会给docker容器分配一个ip,只要我们安装了docker,就会有一个网卡docker0
桥接模式,使用的是veth-pair技术!
2、再次测试,
再启动一个容器测试,发现又多了一对网卡!#
# 我们发现这个容器带来的网卡,都是一对对的! # veth-pair 就是一对的虚拟设备接口,他们都是成对出现的,他们一段连接着协议,一段彼此相连! # 正因为这个特性,veth-pair 充当一个桥梁,连接各种虚拟网络设备的 # OpenStac,Docker容器之间的连接,OVS的连接,都是使用 veth-pair技术
3、我们来测试一下tomcat01 和 tomcat02是否可以ping通!
[root@localhost tomcat]# docker exec -it tomcat01 ping 172.17.0.3 PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data. 64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.168 ms 64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.107 ms 64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.081 ms 64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.080 ms # 结论:容器与容器之间是可以ping通的!
4、绘制一个网络模型图
结论: tomcat01 和 tomcat02 是公用一个路由器的,dockers0
所有容器再不指定网络的情况下,都是docker0来路由的,dockers会给我们的容器的分配一个默认可用的ip
总结
Docker 利用的就是Linux中的桥接,宿主机中是一个docker容器的网桥,docker0!
Docker中的所有网络接口都是虚拟的。原因:虚拟的转发效率高!
只用容器删除, 对应网桥一对就没有了
--link
思考一个场景,我们编写一个微服务,database url=ip;项目不能启动,数据ip换掉了,我们希望去解决这个问题,可以名字来进行访问容器?
[root@localhost tomcat]# docker exec -it tomcat03 ping tomcat01 ping: tomcat01: Name or service not known # 如何解决呢? # 通过 --link可以解决ei网络连通问题 [root@localhost tomcat]# docker run -d -P --name tomcat03 --link tomcat02 diytomcat 73a3aef3950804192873ca9bdd96f95de4ac12e18866cffa52906271cddc03ab [root@localhost tomcat]# 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.630 ms 64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.065 ms # 方向可不可以ping通?
探究:inspect
本质探究:--link 就是我们在hosts配置当中增加了一个172.17.0.3 tomcat02 7a95f0556a06
自定义网络
查看所有docker网络
网络模式
bridge : 桥接 docker (默认,自己创建的时候也使用bridge!)
none : 不配置网路
host : 和宿主机共享网络
container: 容器网络连通!(用的少,局限很大)
测试
# 我们直接启动的命令, --net bridge ,而这个就是我们的docker0 docker run -d -P --net bridge tomcat # docker0特点: 默认,域名 不能访问 --link可以打开连通! # 我们可以自定义一个网络! # --driver bridge # --subnet 192.168.0.0/16 子网地址 # --gateway 192.168.0.1 网关 [root@localhost tomcat]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet 13fe1bf824e4ed5d90732dc61c62a81feb9e6c34c8ed8788d5b25ad80f2ca541 [root@localhost tomcat]# docker network ls NETWORK ID NAME DRIVER SCOPE 93186e393c04 bridge bridge local bd2345398bce host host local 13fe1bf824e4 mynet bridge local 6ea029315d4a none null local [root@localhost tomcat]#
我们自己的网络就创建好了!
测试:
[root@localhost tomcat]# docker run -d -P --name tomcat-net-02 --net mynet diytomcat eda7aa33fce92745b6a0595fef88517eebd01e0db52bfdbcf1b5b8f5f1660735 [root@localhost tomcat]# docker run -d -P --name tomcat-net-01 --net mynet diytomcat 76fad65540ef7e58c672f16ac67b30a62c9221845a5cd72dd3be5ebd27f6631e [root@localhost tomcat]# docker network inspect mynet [ { "Name": "mynet", "Id": "13fe1bf824e4ed5d90732dc61c62a81feb9e6c34c8ed8788d5b25ad80f2ca541", "Created": "2024-01-19T00:15:46.919247251+08:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "192.168.0.0/16", "Gateway": "192.168.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "76fad65540ef7e58c672f16ac67b30a62c9221845a5cd72dd3be5ebd27f6631e": { "Name": "tomcat-net-01", "EndpointID": "410f674d97b43b72c24203cc5f75bb145c9ffa83eaa6cbf625dc07fa619e66c3", "MacAddress": "02:42:c0:a8:00:03", "IPv4Address": "192.168.0.3/16", "IPv6Address": "" }, "eda7aa33fce92745b6a0595fef88517eebd01e0db52bfdbcf1b5b8f5f1660735": { "Name": "tomcat-net-02", "EndpointID": "6676d094cd90876700a3b711e642730d0e003f263346cf7f2315fec8290d1f21", "MacAddress": "02:42:c0:a8:00:02", "IPv4Address": "192.168.0.2/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ] # 再次测试ping连接 [root@localhost tomcat]# docker exec -it tomcat-net-01 ping 192.168.0.2 PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data. 64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.670 ms 64 bytes from 192.168.0.2: icmp_seq=2 ttl=64 time=0.110 ms 64 bytes from 192.168.0.2: icmp_seq=3 ttl=64 time=0.089 ms 64 bytes from 192.168.0.2: icmp_seq=4 ttl=64 time=0.078 ms # 现在不使用--link也可以ping 名字了! [root@localhost tomcat]# docker exec -it tomcat-net-01 ping tomcat-net-02 PING tomcat-net-02 (192.168.0.2) 56(84) bytes of data. 64 bytes from tomcat-net-02.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.136 ms 64 bytes from tomcat-net-02.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.087 ms 64 bytes from tomcat-net-02.mynet (192.168.0.2): icmp_seq=3 ttl=64 time=0.136 ms 64 bytes from tomcat-net-02.mynet (192.168.0.2): icmp_seq=4 ttl=64 time=0.078 ms
我们自定义的网络docker都已经为我们维护好了对应的关系,推荐平时使用自定义的网络!
好处:
redis -- 不同的集群使用不同的网络,保证集群是健康和安全的
mysql-- 不同的集群使用不同的网络,保证集群是健康和安全的
网络连通
# 测试打通 tomcat01 - mynet # 连通以后就是将 tomcat 放到 mynet 网络下? # 一个容器两个ip地址! # 阿里云服务:公网ip 私网ip
# 01 能够ping通 [root@localhost tomcat]# docker exec -it tomcat01 ping tomcat-net-01 PING tomcat-net-01 (192.168.0.3) 56(84) bytes of data. 64 bytes from tomcat-net-01.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.462 ms 64 bytes from tomcat-net-01.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.077 ms 64 bytes from tomcat-net-01.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.103 ms # 02不能ping通 [root@localhost tomcat]# docker exec -it tomcat02 ping tomcat-net-01 ping: tomcat-net-01: Name or service not known
结论:假设要跨网络操作别人,就需要使用docker network connect 连通!
实战:部署Redis集群
这是一个单独的集群,需要做一个单独的网卡!
docker 搭建redis集群完成!
使用docker后,所有的技术就会变得越来越简单
SpringBoot微服务打包成Docker镜像
1、创建springboot项目
2、打包应用
3、编写Dockerfile
4、构建镜像
5、发布运行!
以后我们使用了Docker之后,给别人交付的就是一个镜像即可!