Docker
根据B站狂神Docker视频整理的相关笔记
学习视频地址:
目录
说明:有了镜像才可以创建容器,Linux,下载一个CentOS镜像来学习
【狂神说Java】Docker最新超详细版教程通俗易懂_哔哩哔哩_bilibili
Docker官网:Empowering App Development for Developers | Docker
官网文档:Docker Documentation | Docker Documentation
dockerhub:Docker Hub
帮助文档的地址:Reference documentation | Docker Documentation
- Docker概述
- Docker安装
- Docker命令:
-
- 镜像命令
- 容器命令
-
- 操作命令
- ....
- Docker镜像
- 容器数据卷
- DockerFile
- Docker网络原理
- IDEA整合Docker
- Docker Compose
- Docker Swarm
- CI\CD Jenkins
即使再小的帆也能远航
只要学不死,就往死里学
Docker概述
Docker为什么出现?
一款产品:开发--上线 两套环境!应用环境,应用配置!
开发 -运维。问题:我在我的电脑上可以运行!版本更新,导致服务不可用!对于运维来说,考验就十分大?
环境配置是十分的麻烦,每一个机器都要部署环境(集群Redis、ES、Hadoop.) !费时费力。
发布一个项目 (jar + ( Redis MysQL jdk ES)),项目能不能都带上环境安装打包!
之前在服务器配置一个应用的环境 Redis MysQL jdk ES Hadoop, 配置超麻烦了,不能够跨平台。
Windows,最后发布到 Linux !
传统:开发jar,运维来做!
现在:开发打包部署上线,一套流程做完
Docker的历史
vm: Linux centos原生镜像(一个电脑!) 隔离,需要开启多个虚拟机! 几个G 几分钟
docker: 隔离,镜像(最核心的环境 4M+jdk+mysql)十分小巧,运行镜像就可以了!几个M KB 秒级启动
官网:Empowering App Development for Developers | Docker
文档地址:Docker Documentation | Docker Documentation
dockerhub:Docker Hub
Docker能干嘛
之前的虚拟机技术:
容器化技术:
容器化技术不是模拟一个完整的操作系统
比较Docker和虚拟机技术的不同:
- 传统虚拟机,模拟出一套硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件
- 容器内的应用直接运行在宿主机的内容,容器是没有自己的内核的,也没有虚拟我们的硬件,所以就轻便了
- 每个容器间是互相隔离,每个容器内都有一个属于自己的文件系统,互不影响
DevOps(开发、运维)
Docker是内核级别的虚拟化,可以在一个物理机上可以运行很多的容器实例!服务器的 性能可以被压榨到极致
Docker安装
Docker的基本组成
镜像(image):
docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,tomcat镜像==> run ==>tomcat01容器(提供服务器),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)
容器(container):
Docker利用容器技术,独立运行一个或者一个组应用,通过镜像来创建的
启动,停止,删除,基本命令!
目前就可以把这个容器理解为就是一个简易的Linux系统
仓库(repository):
仓库就是存放镜像的地方!
仓库分为公有仓库和私有仓库!
Docker Hub(默认是国外的)
阿里云...都有容器服务器(配置镜像加速!)
安装Docker
环境准备
环境查看
安装
下载Docker:Get Docker | Docker Documentation
帮助文档:Install Docker Engine on CentOS | Docker Documentation
#1.卸载旧的版本 sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine #2.需要的安装包 sudo yum install -y yum-utils #3.设置镜像的仓库 sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo #默认是从国外的! #推荐使用阿里云!! sudo yum-config-manager \ --add-repo \ https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #更新软件包索引 yum makecache fast #4.安装docker docker-ce社区版 ee企业版 sudo yum install docker-ce docker-ce-cli containerd.io #5.启动Docker sudo systemctl start docker #6.使用docker version查看是否安装成功 docker version #7.运行hello-world docker run hello-world
#8.查看一下下载的hello-world镜像 docker images
卸载docker
#1.卸载依赖 sudo yum remove docker-ce docker-ce-cli containerd.io #2.删除资源 sudo rm -rf /var/lib/docker #docker的默认工作路径 sudo rm -rf /var/lib/containerd
阿里云镜像加速
1.登陆阿里云,从产品与服务中找到容器镜像服务
2.找到镜像加速地址
-容器镜像服务/镜像中心/镜像加速器
3.配置使用
#Ubuntu与CentOS中 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://b4dl3sxl.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker
回顾HelloWorld流程:
run的运行流程分析图:
底层原理
Docker是怎么工作的?
Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上。通过Socket从客户端访问!
DockerServer接收到Docker- Client的指令,就会执行这个命令!
Docker为什么比VM快?
1.Docker有着比虚拟机更少的抽象层
2.Docker利用的是宿主机的内核,VM需要是Guest OS
所以说,新建一个容器的时候,docker不需要像虚拟机一样重新加载一个操作系统的内核,避免引导。虚拟机是加载Guest OS,分钟级别的,而docker是利用宿主机的操作系统,省略了这个复杂的过程,秒级!
Docker的常用命令:
帮助命令:
docker version #显示docker的版本信息 docker info #显示docker的系统信息,包括镜像和容器的数量 docker 命令 --help #帮助命令 docker --help
帮助文档的地址:Reference documentation | Docker Documentation
镜像命令
docker images
查看所有本地的主机上的镜像
#解释
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的ID
CREATED 镜像的创建时间
SIZE 镜像的大小
#可选项
-a, --all #列出所有镜像
-q, --quiet #只显示镜像的ID
docker search 搜索镜像
例:docker search mysql
#可选项,通过收藏来过滤
--filter=STARS=3000 搜索出来的镜像就是STARS大于3000的
docker pull 下载镜像
#下载镜像 docker pull 镜像名[:tag]
docker pull mysql docker pull --platform linux/x86_64 mysql #M1 mac Using default tag: latest #如果不写tag,默认就是latest latest: Pulling from library/mysql ffbb094f4f9e: Pull complete #分层下载,docker image的核心 联合文件系统 df186527fc46: Pull complete fa362a6aa7bd: Pull complete 5af7cb1a200e: Pull complete 949da226cc6d: Pull complete bce007079ee9: Pull complete eab9f076e5a3: Pull complete 8a57a7529e8d: Pull complete b1ccc6ed6fc7: Pull complete b4af75e64169: Pull complete 3aed6a9cd681: Pull complete 23390142f76f: Pull complete Digest: sha256:ff9a288d1ecf4397967989b5d1ec269f7d9042a46fc8bc2c3ae35458c1a26727 #签名 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 docker pull --platform linux/x86_64 mysql:5.7 #M1 mac 5.7: Pulling from library/mysql ffbb094f4f9e: Already exists df186527fc46: Already exists fa362a6aa7bd: Already exists 5af7cb1a200e: Already exists 949da226cc6d: Already exists bce007079ee9: Already exists eab9f076e5a3: Already exists c7b24c3f27af: Pull complete 6fc26ff6705a: Pull complete bec5cdb5e7f7: Pull complete 6c1cb25f7525: Pull complete Digest: sha256:d1cc87a3bd5dc07defc837bc9084f748a130606ff41923f46dec1986e0dc828d Status: Downloaded newer image for mysql:5.7 docker.io/library/mysql:5.7
docker rmi 删除镜像
docker rmi -f 镜像ID #删除指定的镜像 docker rmi -f 镜像ID 镜像ID 镜像ID #删除多个镜像,批量删除 docker rmi -f $(docker images -aq) #删除全部镜像
容器命令
说明:有了镜像才可以创建容器,Linux,下载一个CentOS镜像来学习
docker pull centos
新建容器并启动
docker run [可选参数] image # 参数说明 --name="Name" 容器名字 tomcat01 tomcat02, 用来区分容器 -d 后台方式运行 -it 使用交互方式运行,进入容器查看内容 -p 指定容器的端口 -p 8080:8080 -p ip:主机端口:容器端口 -p 主机端口:容器端口(常用) -p 容器端口 容器端口 -P 随机指定端口 #测试,启动并进入容器 [aiyaowei@Macintosh installextend % docker run -it centos /bin/bash [root@4c0f4c34b84a /]# ls #查看容器内的centos,基础版本,很多命令都是不完善的 bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var #从容器中退出主机 [root@4c0f4c34b84a /]# exit
列出所有运行的容器
#docker ps 命令 #列出当前正在运行的容器 -a #列出当前正在运行的容器+带出历史运行过的容器 -n=? #显示最近创建的容器 -q #只显示容器的编号 aiyaowei@Macintosh installextend % docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES aiyaowei@Macintosh installextend % docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4c0f4c34b84a centos "/bin/bash" 3 minutes ago Exited (0) About a minute ago inspiring_leakey c88dde351e59 hello-world "/hello" 20 hours ago Exited (0) 18 hours ago vigorous_sinoussi
退出容器
exit #直接容器停止并退出 Ctrl + P + Q # 容器不停止退出
删除容器
docker rm 容器ID #删除指定的容器,不能删除正在运行的容器,如果要强制删除 rm -f,即docker rm -f 容器ID docker rm -f $(docker ps -aq) #删除所有的容器 docker ps -a -q|xargs docker rm #删除所有的容器
启动和停止容器的操作
docker start 容器ID #启动容器 docker restart 容器ID #重启容器 docker stop 容器ID #停止当前正在运行的容器 docker kill 容器ID #强制停止当前容器
常用的其他命令
后台启动容器
#命令 docker run -d 镜像名! aiyaowei@Macintosh local % docker run -d centos #问题docker ps,发现centos停止了 #常见的坑:docker 容器使用后台运行,就必须要有一个前台进程,docker发现没有应用,就会自动停止 #nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了
查看日志
docker logs -f -t --tail 容器,没有日志 # 自己编写一段shell脚本 aiyaowei@Macintosh local % docker run -d centos /bin/sh -c "while true;do echo kuangshen;sleep 1;done" bea126167778424f60103eb45bfc6a54b05ba8a9358bce4ca0db85ad518c7188 # aiyaowei@Macintosh local % docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bea126167778 centos "/bin/sh -c 'while t…" 2 seconds ago Up 2 seconds flamboyant_poincare # 显示日志 -tf #显示日志 --tail number #要显示日志条数 aiyaowei@Macintosh local % docker logs -tf --tail 10 bea126167778
查看容器中进程信息 ps
# 命令 docker top 容器ID aiyaowei@Macintosh local % docker top bea126167778 UID PID PPID C STIME TTY TIME CMD root 2959 2934 0 02:18 ? 00:00:00 /bin/sh -c while true;do echo kuangshen;sleep 1;done root 3364 2959 0 02:24 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1
查看镜像的元数据
# 命令 docker inspect 容器ID # 测试 aiyaowei@Macintosh local % docker inspect bea126167778 [ { "Id": "bea126167778424f60103eb45bfc6a54b05ba8a9358bce4ca0db85ad518c7188", "Created": "2021-12-10T02:18:44.53711168Z", "Path": "/bin/sh", "Args": [ "-c", "while true;do echo kuangshen;sleep 1;done" ], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 2959, "ExitCode": 0, "Error": "", "StartedAt": "2021-12-10T02:18:44.721647597Z", "FinishedAt": "0001-01-01T00:00:00Z" }, "Image": "sha256:e6a0117ec169eda93dc5ca978c6ac87580e36765a66097a6bfb6639a3bd4038a", "ResolvConfPath": "/var/lib/docker/containers/bea126167778424f60103eb45bfc6a54b05ba8a9358bce4ca0db85ad518c7188/resolv.conf", "HostnamePath": "/var/lib/docker/containers/bea126167778424f60103eb45bfc6a54b05ba8a9358bce4ca0db85ad518c7188/hostname", "HostsPath": "/var/lib/docker/containers/bea126167778424f60103eb45bfc6a54b05ba8a9358bce4ca0db85ad518c7188/hosts", "LogPath": "/var/lib/docker/containers/bea126167778424f60103eb45bfc6a54b05ba8a9358bce4ca0db85ad518c7188/bea126167778424f60103eb45bfc6a54b05ba8a9358bce4ca0db85ad518c7188-json.log", "Name": "/flamboyant_poincare", "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, "CgroupnsMode": "private", "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": null, "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/e95f7a1f81e7ab28ac6b1c4e18f6786d3544335dc3617ecc4dc59201eced7a27-init/diff:/var/lib/docker/overlay2/7ecea0098445ea5e1e3b36c9d674bee5a7be0b8e2c58e21ce46fdd8db1dc6abf/diff", "MergedDir": "/var/lib/docker/overlay2/e95f7a1f81e7ab28ac6b1c4e18f6786d3544335dc3617ecc4dc59201eced7a27/merged", "UpperDir": "/var/lib/docker/overlay2/e95f7a1f81e7ab28ac6b1c4e18f6786d3544335dc3617ecc4dc59201eced7a27/diff", "WorkDir": "/var/lib/docker/overlay2/e95f7a1f81e7ab28ac6b1c4e18f6786d3544335dc3617ecc4dc59201eced7a27/work" }, "Name": "overlay2" }, "Mounts": [], "Config": { "Hostname": "bea126167778", "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 kuangshen;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": "dd8103193ef4e5b0c57a509b60d34da337ec6f584a51e8932eb9a6c554447fd5", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": {}, "SandboxKey": "/var/run/docker/netns/dd8103193ef4", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "5a059630e945d9790670fdc397fb1f760109f55fcd8723e1c67f67b79953ddd2", "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": "b5d0826bdb61d42094ce81894b3f92991484425db8f258742307a6113db1eac1", "EndpointID": "5a059630e945d9790670fdc397fb1f760109f55fcd8723e1c67f67b79953ddd2", "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 # 测试 aiyaowei@Macintosh local % docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bea126167778 centos "/bin/sh -c 'while t…" 3 hours ago Up 3 hours flamboyant_poincare aiyaowei@Macintosh local % docker exec -it bea126167778 /bin/bash [root@bea126167778 /]# ls bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var [root@bea126167778 /]# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 02:18 ? 00:00:11 /bin/sh -c while true;do echo kuangshen;sleep 1;done root 11436 0 0 05:30 pts/0 00:00:00 /bin/bash root 11465 1 0 05:30 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1 root 11466 11436 0 05:30 pts/0 00:00:00 ps -ef # 方式二 docker attach 容器ID # 测试 aiyaowei@Macintosh local % docker attach bea126167778 # docker exec # 进入容器后开启一个新的终端,可以在里面操作(常用) # docker attach # 进入容器正在执行的终端,不会启动新的进程
从容器内拷贝文件到主机上面
docker cp 容器ID:容器内路径 目的的主机路径 # 测试 # 查看当前主机目录下 aiyaowei@Macintosh Desktop % ls kuangshen.java # 进入正在运行的容器 aiyaowei@Macintosh Desktop % docker attach 8963a3f0967b [root@8963a3f0967b /]# ls bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var [root@8963a3f0967b /]# cd home [root@8963a3f0967b home]# ls # 在容器下新建一个文件test.java [root@8963a3f0967b home]# touch test.java [root@8963a3f0967b home]# ls test.java # 关闭并停止容器 [root@8963a3f0967b home]# exit exit # 列出当前正在运行的容器或历史运行过的容器 aiyaowei@Macintosh Desktop % docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8963a3f0967b centos "/bin/bash" 2 minutes ago Exited (0) 9 seconds ago clever_sutherland # 将容器内的文件拷贝到主机的当前文件夹下 aiyaowei@Macintosh Desktop % docker cp 8963a3f0967b:/home/test.java ./ aiyaowei@Macintosh Desktop % ls test.java kuangshen.java # 拷贝是一个手动过程,未来我们使用 -v 卷的技术,可以实现,自动同步
小结
attach Attach to a running container #当前shell下attach连接指定运行镜像 build Build an image from a Dockerfile #通过Dockerfile定制镜像 commit Create a new image from a container changes #提交当前容器为新的镜像 cp Copy files/folders from the containers filesystem to the host path #从容器中拷贝指定文件或者目录到宿主机中 create Create a new container #创建一个新的容器,同run,但不启动容器 diff Inspect changes on a container's filesystem #查看docker容器变化 events Get real time events from the server #从docker服务获取容器实时事件 exec Run a command in an existing container #在已存在的容器上运行命令 export Stream the contents of a containers as a tar archive #导出容器的内容流作为一个tar归档文件[对应import] history Show the history of an image #展示一个镜像形成历史 images List images #列出系统当前镜像 import Create a new filesystem image from the contents of a tarball #从tar包中的内容创建一个新的文件系统映像[对应export] info Display system-wide information #显示系统相关信息 inspect Return low-level information on a container #查看容器详细信息 kill Kill a running container #kill指定docker容器 load Load an image from a tar archive #从一个tar包中加载一个镜像[对应save] login Register or Login to the docker registry server #注册或者登陆一个docker源服务器 logout Log out from a Docker registry server #从当前Docker registry退出 logs Fetch the logs of a container #输出当前容器日志信息 port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT #查看映射端口对应的容器内部源端口 pause Pause all processes within a container #暂停容器 ps List containers #列出容器列表 pull Pull an image or a repository from the docker registry server #从docker镜像源服务器拉取指定镜像或者库镜像 push Push an image or a repository to the docker registry server # 推送指定镜像或者库镜像至docker源服务器 restart Restart a running container #重启运行的容器 rm Remove one or more containers #移除一个或者多个容器 rmi Remove one or more images #移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续 或者 -f 强制删除] run Run a command in a new container #创建一个新的容器并运行一个命令 save Save an image to a tar archive #保存一个镜像为一个tar包[对应load] search Search for an image on the Docker Hub #在docker hub中搜索镜像 start Start a stopped containers #启动容器 stop Stop a running containers #停止容器 tag Tag an image into a repository #给源中镜像打标签 top Lookup the running processes of a container #查看容器中运行的进程信息 unpause Unpause a paused container #取消暂停容器 version Show the docker version information #查看docker版本号 wait Block until a containers stops, then print its exit code #截取容器停止时的退出状态值
docker安装nginx
# 1.搜索镜像 search 建议去dockerhub上去搜索 docker search nginx # 2.下载镜像 pull docker pull nginx # 3.运行测试 将启动的nginx镜像命名为nginx01,通过公网的3344端口来访问docker中的80端口 docker run -d --name nginx01 -p 3344:80 nginx # -d 后台运行 # --name 给容器命名 # -p 宿主机端口:容器内部端口 # 进入容器 aiyaowei@Macintosh Desktop % docker exec -it nginx01 /bin/bash root@d44230d73a1d:/# whereis nginx nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx root@d44230d73a1d:/# cd /etc/nginx root@d44230d73a1d:/etc/nginx# ls conf.d fastcgi_params mime.types modules nginx.conf scgi_params uwsgi_params
端口暴露的概念:
思考问题:我们每次改动nginx配置文件,都需要进入容器内部?十分的麻烦,我要是可以在容器外部提供一个映射路径,达到在容器修改文件名,容器内部就可以自动修改?-v 数据卷!
docker安装tomcat
# 官方的使用 docker run -it --rm tomcat:9.0 # 我们之前的启动都是后台,停止了容器之后,容器还是可以查到 docker run -it --rm,一般用来测试,用完即删 # 下载再启动 docker pull tomcat # 启动运行 docker run -d -p 3355:8080 --name tomcat01 tomcat # 测试访问没有问题 # 进入容器 docker exec -it tomcat01 /bin/bash # 发现问题 1.Linux命令少了 2.没有webapps 阿里云镜像的原因,默认是最小的镜像,所有不必要的都剔除掉。 # 保证最小可运行的环境!
思考问题:我们以后要部署项目,如果每次都要进入容器是不是十分麻烦?我要是可以在容器外部提供一个映射路径,webapps,我们在外部放置项目,就自动同步到内部就好了!
问题:
原因:阉割版
解决:webapps中无任何文件,执行cp -r webapps.dist/* webapps
将内容拷贝到webapps中,再重新刷新即可
docker部署ES+kibana
# es暴露的端口很多! # es十分的耗内存 # es的数据一般需要放置到安全目录!挂载 # --net somenetwork ? 网络配置 # 启动 elasticsearch docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2 # M1 Mac 启动 elasticsearch docker run --platform linux/x86_64 -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2 # 启动了 Linux就卡住了 docker stats 查看cpu的状态 # 测试一下es是否成功 curl localhost:9200 { "name" : "51921ed8871c", "cluster_name" : "docker-cluster", "cluster_uuid" : "a5VPElk1Sc-Wmf58p06grw", "version" : { "number" : "7.14.2", "build_flavor" : "default", "build_type" : "docker", "build_hash" : "6bc13727ce758c0e943c3c21653b3da82f627f75", "build_date" : "2021-09-15T10:18:09.722761972Z", "build_snapshot" : false, "lucene_version" : "8.9.0", "minimum_wire_compatibility_version" : "6.8.0", "minimum_index_compatibility_version" : "6.0.0-beta1" }, "tagline" : "You Know, for Search" } # es是十分耗内存的,1.xG 1核2G # 查看docker stats # 赶紧关闭,增加内存的限制
ES很占内存
# 赶紧关闭,增加内存的限制,修改配置文件 -e 环境配置修改 # 启动 elasticsearch docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2 # M1 Mac 启动 elasticsearch docker run --platform linux/x86_64 -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch
报错:需要更换名称,例
需要更换名称,例:
docker run --platform linux/x86_64 -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch
M1Mac出现启动后立即停止的情况,docker中提示:
执行:docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.14.2
内存占用过大,设置内存:
docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" docker.elastic.co/elasticsearch/elasticsearch:7.14.2
作业:使用kibana连接elasticsearch?思考网络如何才能连接过去?
可视化
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?
Docker图形化界面管理工具!提供一个后台面板供我们操作!
docker run -d -p 8088:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
访问测试:外网:8088 http://localhost:8088/
通过它来访问了:
选择本地的:
进入之后的面板:
可视化面板我们平时不会使用,测试玩玩即可
Docker镜像讲解:
镜像是什么:
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
所有的应用,直接打包docker镜像,就可以直接跑起来!
如何得到镜像:
- 从远程仓库下载
- 朋友拷贝给你
- 自己制作一个镜像DockerFile
Docker镜像加载原理:
UnionFS(联合文件系统)
我们下载的时候看到的一层层就是这个!
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs(root file system),在bootfs之上。包含的就是典型Linux系统中/dev,/proc,/bin,/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么Docker这里才200M?
对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。
虚拟机是分钟级别,容器是秒级!
分层理解
分层的镜像
我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!
思考:为什么Docker镜像要采用这种分层的结构呢?
最大的好处,我觉得莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。
查看镜像分层的方式可以通过docker image inspect
命令!
下载redis
docker pull redis
docker image inspect redis:latest
"RootFS": { "Type": "layers", "Layers": [ "sha256:68335b4e9d88f4353f9ffd28d045e4bb33381c77633a41b8e9c13de1181eb53c", "sha256:86d72800a3f4b191d9586dab621deb2ffc9375e091240bb9c5b256a383c2d7ea", "sha256:8e057435829564fd2992907d8df7a880129b53e32304a38162c3a2e3c48c1e02", "sha256:a8298647de52a3172c64f7405eee0ef125369b5444b7b4ba1bbf3f0b63947fa4", "sha256:b3e7734b7bd4308160b1197a921a63b6dfa3f6e16b8f4d592013c0a06bcfec7c", "sha256:0ebca69bb3399fd8d6bc23d8b06b576d44d81190425d12e4ce2eea8f45b47e0e" ] },
理解:
所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于Ubuntu Linux 16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。
该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。
这种情况下,上层镜像中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。
Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
Linux上可用的存储引擎有AUFS、Overlay2、Device Mapper、Btrfs以及ZFS。顾名思义,每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。
Docker在Windows上仅支持 windowsfilter一种存储引擎,该引擎基础NTFS文件系统之上实现了分层和CoW[1]。
下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。
特点
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!
如何提交一个自己的镜像
commit镜像
docker commit 提交容器成为一个新的副本 # 命令和git原理类似 docker commit -m="提交的描述信息" -a="作者" 容器ID 目标镜像名:[TAG]
实战测试:
# 1.启动一个默认的tomcat docker run -it -p 8080:8080 tomcat docker exec -it f835d08a42fd /bin/bash # 2.发现这个默认的tomcat 是没有webapps应用,镜像的原因,官方的镜像默认webapps上是没有文件的! root@f835d08a42fd:/usr/local/tomcat# cd webapps root@f835d08a42fd:/usr/local/tomcat/webapps# ls # 3.我自己拷贝进去了基本的文件 cp -r webapps.dist/* webapps # 4.将我们操作过的容器通过commit提交为一个镜像!我们以后就使用我们修改过的镜像即可,这就是我们自己的一个修改过的镜像 aiyaowei@Macintosh / % docker ps f835d08a42fd tomcat docker commit -a="aiyaowei" -m="add webapps app" f835d08a42fd tomcat02:1.0 docker images
docker run -it -p 8080:8080 tomcat
docker ps
docker exec -it f835d08a42fd /bin/bash
cp -r webapps.dist/* webapps
学习方式说明:理解概念,但是一定要实践,最后实践和理论相结合一次搞定这个知识
如果你想要保存当前容器的状态,就可以通过commit来提交,获得一个镜像,就好比我们以前学习VM的时候,快照!
到了这里才算是入门docker,认真吸收练习,该休息!
Docker精髓:
容器数据卷
什么是容器数据卷
docker的理念回顾
将应用和环境打包成一个镜像!
数据?如果数据都在容器中,那么我们容器删除,数据就会丢失!需求:数据可以持久化
Mysql,容器删了,删库跑路! 需求:Mysql数据可以存储在本地!
容器之间可以有一个数据共享的技术!Docker容器中产生的数据,同步到不笨!
这就是卷技术!目录的挂载,将我们容器内的目录,挂载到Linux上面!
总结一句话:容器的持久化和同步操作!容器间也是可以数据共享的!
使用数据卷
方式一:直接使用命令来挂载 -v
docker run -it -v 主机目录:容器内目录 # 测试 docker run -it -v /usr/local/dockerfile:/home centos /bin/bash # 因本地目录的原因导致拉取失败 docker run -it -v /Users/centos/centosfile:/home centos /bin/bash #成功 # 启动起来之后,可以通过docker inspect 容器ID
注:可能会因为权限问题导致文件夹或文件未创建,在某些特殊的文件夹下,例上图/usr/local会导致文件创建失败,可更换普通的目录下测试
同步的过程,双向绑定,容器与主机内的文件一致,容器内文件变化可同步到主机上,主机上文件变化也可同步到容器内
停止容器,在宿主机上修改文件,启动容器后,容器内的数据依旧是同步的
好处:我们以后修改只需要在本地修改即可,容器内会自动同步
实战:安装MySQL
思考:Mysql的数据持久化的问题
# 搜索镜像 docker search mysql # 获取镜像 docker pull mysql:5.7 docker pull --platform linux/x86_64 mysql:5.7 # M1 Mac # 运行容器,需要做数据挂载 # 安装启动mysql的时候,需要配置密码的,这是要注意点 # 官方测试:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag docker run -d -p 3310:3306 -v /Users/centos/mysql/conf:/etc/mysql/conf.d -v /Users/centos/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7 # 启动我们的 -d 后台运行 -p 端口映射 -v 卷挂载,通过多个-v挂载多个目录 -e 环境配置 --name 容器名字 # 启动成功之后,我们在本地使用Navicat来连接测试一下 # Navicat-连接到服务器到3310 --3310 和容器内到3306映射,这个时候我们就连接上了! # 在本地测试创建一个数据库,查看一下我们映射的路径是否OK
假设我们将容器删除
发现,我们挂载到本地的数据卷依旧没有丢失,这就实现了容器数据持久化功能!
M1mac运行docker run -d -p 3310:3306 -v /Users/centos/mysql/conf:/etc/mysql/conf.d -v /Users/centos/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
报WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
具名和匿名挂载
# 匿名挂载 -v 容器内路径 docker run -d -P --name nginx01 -v /etc/nginx nginx # 查看所有卷的情况 docker volume ls ---------------------------- DRIVER VOLUME NAME local 91bfe2d4864e04e40a2a579208432ec9b0d1071f7675e29c35404fe14c893d6a local b5257be13deaec344bd1310008291c8242c4b89a511d026ee4f4efec91295f19 local c7d6ec3a9b34f146c32741766ace40789cc71122e6adcc02c39d025ea4c51da2 local deeb447d48b5fc1d4e368c31cc6ea1a0f4a9bc5d918d7ec799f3ed136f0e5975 # 这里发现,这种就是匿名挂载,我们在-v的时候只写了容器内的路径,没有写容器外的路径 # 具名挂载 aiyaowei@Macintosh centos % docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx 12043f84090de0b43ba532d3bffcf12685178deabf33052e5e0d9560826b1a91 aiyaowei@Macintosh centos % docker volume ls DRIVER VOLUME NAME local 91bfe2d4864e04e40a2a579208432ec9b0d1071f7675e29c35404fe14c893d6a #匿名 local b5257be13deaec344bd1310008291c8242c4b89a511d026ee4f4efec91295f19 #匿名 local c7d6ec3a9b34f146c32741766ace40789cc71122e6adcc02c39d025ea4c51da2 #匿名 local deeb447d48b5fc1d4e368c31cc6ea1a0f4a9bc5d918d7ec799f3ed136f0e5975 #匿名 local juming-nginx #具名 local laradock_adminer #具名 # 通过 -v 卷名:容器内路径 # 查看一下这个卷
所有的docker容器内的卷,没有指定目录的情况下都是在/var/lib/docker/volumes/xxx/_data
我们通过具名挂载可以方便的找到我们的一个卷,大多数情况在使用的具名挂载
# 如何确定是具名挂载还是匿名挂载,还是指定路径挂载! -v 容器内路径 # 匿名挂载 -v 卷名:容器内路径 #具名挂载 -v /宿主机路径:容器内路径 #指定路径挂载
拓展:
# 通过-v 容器内路径:ro rw改变读写权限 ro readonly #只读 rw readwrite #可读可写 # 一旦设置了容器权限,容器对我们挂载出来的内容就有限定了! aiyaowei@Macintosh / % docker run -d -P --name nginx03 -v juming-nginx:/etc/nginx:ro nginx aiyaowei@Macintosh / % docker run -d -P --name nginx03 -v juming-nginx:/etc/nginx:rw nginx # ro 只要看到ro,就说明这个路径只能通过宿主机来操作,容器内部是无法操作的
初识Dockerfile
Dockerfile就是用来构建docker镜像的构造文件!命令脚本!
通过这个脚本可以生成镜像,镜像是一层一层的,脚本一个个的命令,每个命令都是一层!
# 创建一个dockerfile文件,名字可以随机,建议Dockerfile,比如在/Users/centos/docker-test-volume下创建dockerfile1文件, # 文件中内容 指令(大写) 参数 FROM centos VOLUME ["volume01","volume02"] CMD echo "----end----" CMD /bin/bash # 这里的每个命令,就是镜像的一层!
# 执行 docker build -f /Users/centos/docker-test-volume/dockerfile1 -t kuangshen/centos:1.0 .
这个卷和外部一定有一个同步的目录
查看一下卷挂载的路径
测试一下刚才的文件是否同步出去了
这种方式我们未来使用十分多,因为我们通常会构建自己的镜像!
假设构建镜像的时候没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径!
数据卷容器
多 个mysql同步数据!
# 启动3个容器,通过刚才写的镜像启动
(创建了docker01,之后的02和03是挂载的01的卷,后删除docker01,发现02和03还可以访问卷) # 测试:可以删除docker01,查看一下docker02和docker03,是否还可以访问这个文件 # 测试依旧可以访问 相当于三个容器里的文件硬连接到宿主机下面
多个mysql实现数据共享
docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7 docker run -d -p 3311:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volume-from mysql01 mysql:5.7 # 这个时候,可以实现两个容器数据同步!
结论:
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止
但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的!
DockerFile
DockerFile介绍
dockerfile是用来构建docker镜像的文件!命令参数脚本!
构建步骤:
1.编写一个dockerfile文件
2.docker build构建成为一个镜像
3.docker run运行镜像
4.docker push 发布镜像(DockerHub、阿里云镜像仓库)
查看一下官方是怎么做的?
很多官方镜像都是基础包,很多功能没有,我们通常会自己搭建自己的镜像!
官方既然可以制造镜像,那我们也可以!
DockerFile构建过程
基础知识:
- 每个保留关键字(指令)都必须是大写字母
- 执行从上到下顺序执行
- #表示注释
- 每一个指令都会创建提交一个新的镜像层,并提交
dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单!
Docker镜像逐渐成为了企业交付的标准,必须要掌握!
步骤:开发,部署,运维。。。缺一不可!
DockerFile:构建文件,定义了一切的步骤,源代码
DockerImages:通过DockerFile构建生成的镜像,最终要发布和运行的产品!
Docker容器:容器就是镜像运行起来提供服务的
DockerFile的指令
以前的话我们就是使用别人的,现在我们知道了这些指令后,我们来练习自己写一个镜像!
FROM # 基础镜像,一切从这里开始构建 centos MAINTAINER # 镜像是谁写的,姓名+邮箱 RUN # 镜像构建的时候需要运行的命令 ADD # 步骤:tomcat镜像,zhege tomcat压缩包!添加内容 WORKDIR # 镜像的工作目录 VOLUME # 挂载的目录 EXPOSE # 暴露端口配置 CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代 例如cmd echo ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令 ONBUILD # 当构建一个被继承DockerFile这个时候就会运行ONBUILD指令。触发指令。 COPY # 类似ADD命令,将我们文件拷贝到镜像中 ENV # 构建的时候设置环境变量
实战测试
Docker Hub中99%镜像都是从这个基础镜像过来的FROM scratch,然后配置需要的软件和配置来进行构建的
创建一个自己的centos
# 1. 编写Dokerfile的文件 FROM centos MAINTAINER aiyaowei<1320223628@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 # 2. 通过这个文件构建镜像 # 命令 docker build -f dockerfile文件路径 -t 镜像名:[tag] . # 3. 测试运行
对比:之前的原生的centos
我们增加之后的镜像:
我们可以列出本地镜像的变更历史
docker history 镜像ID
通过--no-trunc
可以列出完整的信息,不会出现...,例如:docker history 63eb316dc556 --no-trunc
我们平时拿到一个镜像,可以研究一下他是怎么做的了?
CMD和ENTRYPOINT区别
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代 例如cmd echo
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
测试cmd
# 编写dockerfile文件 aiyaowei@Macintosh dockerfile % vim dockerfile-cmd-test FROM centos CMD ["ls","-a"] # build构建镜像 aiyaowei@Macintosh dockerfile % docker build -f dockerfile-cmd-test -t cmdtest . # run运行 , 发现我们的ls -a命令生效 aiyaowei@Macintosh dockerfile % docker run 800ae6f76bf9 . .. .dockerenv bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var # 想追加一个命令 -l ls -al aiyaowei@Macintosh dockerfile % docker run 800ae6f76bf9 -l docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown. ERRO[0000] error waiting for container: context canceled # cmd的情况下 -l 替换了CMD["ls","-a"]命令, -l不是命令所以报错!
测试ENTRYPOINT
aiyaowei@Macintosh dockerfile % vim dockerfile-cmd-entrypoint FROM centos ENTRYPOINT ["ls","-a"] aiyaowei@Macintosh dockerfile % docker build -f dockerfile-cmd-entrypoint -t entrypoint-test . [+] Building 0.1s (5/5) FINISHED => [internal] load build definition from dockerfile-cmd-entrypoint 0.0s => => transferring dockerfile: 92B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/centos:latest 0.0s => CACHED [1/1] FROM docker.io/library/centos 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:9f1a36acb55321d87fe7400634a6d558f473f6905d4caf1c6734e627f2325abc 0.0s => => naming to docker.io/library/entrypoint-test 0.0s Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them aiyaowei@Macintosh dockerfile % docker run 9f1a36acb55321d87fe7400634a6d558f473f6905d4caf1c6734e627f2325abc . .. .dockerenv bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var # 我们的追加命令,是直接拼接在我们的 ENTRYPOINT 命令的后面 aiyaowei@Macintosh dockerfile % docker run 9f1a36acb55321d87fe7400634a6d558f473f6905d4caf1c6734e627f2325abc -l total 56 drwxr-xr-x 1 root root 4096 Dec 15 05:55 . drwxr-xr-x 1 root root 4096 Dec 15 05:55 .. -rwxr-xr-x 1 root root 0 Dec 15 05:55 .dockerenv lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin drwxr-xr-x 5 root root 340 Dec 15 05:55 dev drwxr-xr-x 1 root root 4096 Dec 15 05:55 etc drwxr-xr-x 2 root root 4096 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 4096 Sep 15 14:25 lost+found drwxr-xr-x 2 root root 4096 Nov 3 2020 media drwxr-xr-x 2 root root 4096 Nov 3 2020 mnt drwxr-xr-x 2 root root 4096 Nov 3 2020 opt dr-xr-xr-x 185 root root 0 Dec 15 05:55 proc dr-xr-x--- 2 root root 4096 Sep 15 14:26 root drwxr-xr-x 11 root root 4096 Sep 15 14:26 run lrwxrwxrwx 1 root root 8 Nov 3 2020 sbin -> usr/sbin drwxr-xr-x 2 root root 4096 Nov 3 2020 srv dr-xr-xr-x 13 root root 0 Dec 15 05:55 sys drwxrwxrwt 7 root root 4096 Sep 15 14:26 tmp drwxr-xr-x 12 root root 4096 Sep 15 14:25 usr drwxr-xr-x 20 root root 4096 Sep 15 14:25 var
DockerFile中很多命令都十分的相似,我们需要了解他们的区别,我们最好的学习就是对比他们然后测试效果
实战:Tomcat镜像
- 准备镜像文件 tomcat压缩包,jdk的压缩包!
- 编写dockerfile文件,官方命名Dockerfile,build会自动寻找这个文件,就不需要-f指定了
- 构建镜像
# docker build -t diytomcat .
- 启动镜像
- 访问测试
- 发布项目(由于做了卷挂载,我们直接在本地就可以发布了)
mkdir WEB-INF
cd WEB-INF
vim web.xml
cd WEB-INF/ vim index.jsp
发现:项目部署成功,可以直接访问ok!
我们以后开发的步骤:需要掌握Dockerfile的编写!我们之后的一切都是使用docker镜像来发布运行!
发布自己的镜像
Docker Hub
- 地址Docker Hub注册自己的账号
- 确定这个账号可以登陆
- 在我们服务器上提交自己的镜像
aiyaowei@Macintosh dockerfile % docker login --help Log in to a Docker registry or cloud backend. If no registry server is specified, the default is defined by the daemon. Usage: docker login [OPTIONS] [SERVER] [flags] docker login [command] Available Commands: azure Log in to azure Flags: -h, --help Help for login -p, --password string password --password-stdin Take the password from stdin -u, --username string username Use "docker login [command] --help" for more information about a command.
- 登陆完毕后就可以提交镜像了,就是一步docker push
# push自己的镜像到服务器上 docker push 镜像名 aiyaowei@Macintosh dockerfile % docker push cmdtest Using default tag: latest The push refers to repository [docker.io/library/cmdtest] d871dadfb37b: Preparing denied: requested access to the resource is denied # 拒绝 # push镜像的问题 aiyaowei@Macintosh dockerfile % docker push aiyaowei/cmdtest:2.0 The push refers to repository [docker.io/aiyaowei/cmdtest] An image does not exist locally with the tag: aiyaowei/cmdtest # 解决:增加一个tag docker tag 800ae6f76bf9 aiyaowei/test:1.0 # docker push上去即可!自己发布的镜像尽量带上版本号 aiyaowei@Macintosh dockerfile % docker push aiyaowei/test:1.0 The push refers to repository [docker.io/aiyaowei/test] d871dadfb37b: Pushed 1.0: digest: sha256:71357b1ad81f697e59b3780c2d797fd6dee0dfbb73238502d1441d5f6c497270 size: 529
提交的时候也是按照镜像的层级来进行提交的!
阿里云镜像服务上
- 登陆阿里云
- 找到容器镜像服务
- 创建命名空间
- 创建容器镜像
先创建命名空间,然后创建镜像仓库
- 浏览阿里云
阿里云容器镜像的就参考官方地址!
小结
docker load --help
docker save --help
Docker网络(铺垫 容器编排 集群部署!)
理解Docker0
清空所有环境
测试
三个网络
问题:docker是如何处理容器网络访问的?
# 测试 docker run -d -P --name tomcat01 tomcat # 查看容器的内部网络地址 ip addr docker exec -it tomcat01 ip addr
报错:OCI runtime exec failed
# 进入容器 docker exec -it tomcat01 /bin/bash cd / # 下载相关组件 apt update && apt install -y iproute2 # 可以直接在容器内部执行 ip addr # 也可以ctrl+P+Q退出容器(并不停用) 然后查看IP docker exec -it tomcat01 ip addr
# 思考 Linux能不能ping通容器内部!
linux可以ping通docker容器内部
Mac ping不通:
原理(Linux):
- 我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0,桥接模式,使用的技术是evth-pair技术!
再次测试ip addr
- 再启动一个容器测试,发现又多了一对网卡~
# 我们发现这个容器带来网卡,都是一对对的
# evth-pair就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
# 正因为有这个特性,evth-pair充当一个桥梁,连接各种虚拟网络设备的
# OpenStac,Docker容器之间的连接,OVS的连接,都是使用evth-pair技术
- 我们来测试下tomcat01和tomcat02是否可以ping通!
# 结论:容器和容器之间是可以互相ping通的!
绘制一个网络模型图:
结论:tomcat01和tomcat02是公用的一个路由器,docker0
所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用ip
小结:
Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥 docker0。
Docker中的所有的网络接口都是虚拟的。虚拟的转发效率高!(内网传递文件!)
只要容器删除,对应的网桥一对就没了
--link
思考一个场景,我们编写了一个微服务,database url=ip:项目不重启,数据库ip换掉了,我们希望可以处理这个问题,可以通过名字来访问服务容器?
# 如何可以解决呢?
# 通过--link 就可以解决了网络连通问题
# 反向可以ping通吗?
探究:inspect
docker network ls
docker network inspect dddfeba2f7b7
其实这个tomcat03就是在本地配置了tomcat02的配置?
# 查看hosts配置,在这里原理发现!
本质探究:--link就是我们在hosts配置中增加了一个172.17.0.3 tomcat02 f9994995a9ac
我们现在玩docker已经不建议使用--link了
自定义网络!不适用docker0!
docker0问题:他不支持容器名连接访问!
自定义网络
# 查看所有的docker网络
网络模式
bridge:桥接 docker(默认,自己创建也使用birdge模式)
none:不配置网络
host:和宿主机共享网络
container:容器内网络连通!(用得少!局限性很大)
测试
# 我们直接启动的命令 --net bridge,而这个就是我们的docker0
原:docker run -d -P --name tomcat01 tomcat
现:docker run -d -P --name tomcat01 --net bridge tomcat
# docker0特点:默认,域名不能访问,--link可以打通连接!
# 我们可以自定义一个网络!
# --driver bridge
# --subnet 192.1680.0.0/16 192.168.255.255
# --gateway 192.168.0.1
aiyaowei@Macintosh centos % docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet 9b9a9c4c8610a1d74d477c6bdf66c5114866031907fa7e46f596666fb4ac4063 aiyaowei@Macintosh centos % docker network ls NETWORK ID NAME DRIVER SCOPE dddfeba2f7b7 bridge bridge local 9230e8014288 host host local 5cb46bc7477e laradock_backend bridge local 7c2f77e7bd43 laradock_default bridge local 9b9a9c4c8610 mynet bridge local 7165e750d68d none null local
我们自己的网络就创建好了
aiyaowei@Macintosh centos % docker run -d -P --name tomcat-net-01 --net mynet tomcat 9110f877854e88b716fd9acf88a3dc0fc51eef8d16da6eb61cb41f995b9dbef3 aiyaowei@Macintosh centos % docker run -d -P --name tomcat-net-02 --net mynet tomcat 171a24f144c6cde319ede92a7d99be6b65af2ae6b38f888bf5043cf889bfef92 aiyaowei@Macintosh centos % docker network inspect mynet [ { "Name": "mynet", "Id": "9b9a9c4c8610a1d74d477c6bdf66c5114866031907fa7e46f596666fb4ac4063", "Created": "2021-12-16T08:53:45.352151006Z", "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": { "171a24f144c6cde319ede92a7d99be6b65af2ae6b38f888bf5043cf889bfef92": { "Name": "tomcat-net-02", "EndpointID": "f3025678ea3c14d0aca3893a934f30a9636bb1a90aaf08fb448ed9d7c46e491a", "MacAddress": "02:42:c0:a8:00:03", "IPv4Address": "192.168.0.3/16", "IPv6Address": "" }, "9110f877854e88b716fd9acf88a3dc0fc51eef8d16da6eb61cb41f995b9dbef3": { "Name": "tomcat-net-01", "EndpointID": "e201a2bc2f3ca2e9e90e0edf159bcf903f886063efbcc8c168923b2281678d37", "MacAddress": "02:42:c0:a8:00:02", "IPv4Address": "192.168.0.2/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ]
# 再次测试ping连接
# 现在不适用--link也可以ping名字了!
我们自定义的网络docker都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络
好处:不同的集群使用不同的网络,保证集群是安全和健康的
网络连通
# 测试:打通tomcat01 - mynet
docker network connect mynet tomcat01
# 连通之后就是将tomcat01放到了mynet网络下
docker network inspect mynet
# 一个容器两个ip地址! 阿里云服务,公网ip,私网IP
docker exec -it tomcat01 ping tomcat-net-01
结论:假设要跨网络操作别人,就需要使用docker network connect连通!
实战:部署Redis集群
# 创建网卡 docker network create redis --subnet 172.38.0.0/1 # 通过脚本创建六个redis配置 for port in $(seq 1 6); \ do \ mkdir -p /Users/centos/redis/node-${port}/conf touch /Users/centos/redis/node-${port}/conf/redis.conf cat << EOF >/Users/centos/redis/node-${port}/conf/redis.conf port 6379 bind 0.0.0.0 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 cluster-announce-ip 172.38.0.1${port} cluster-announce-port 6379 appendonly yes EOF done ------------------------------------------------------------------------- for port in $(seq 1 6); \ do \ docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \ -v /Users/centos/redis/node-${port}/data:/data \ -v /Users/centos/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \ -d --net redis --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf \ done ------------------------------------------------------------------------- 上面的脚本相当于执行下面6次 docker run -p 6371:6379 -p 16371:16379 --name redis-1 \ -v /Users/centos/redis/node-1/data:/data \ -v /Users/centos/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \ -d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf docker run -p 6372:6379 -p 16372:16379 --name redis-2 \ -v /Users/centos/redis/node-2/data:/data \ -v /Users/centos/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \ -d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf . . . ------------------------------------------------------------------------- # 进入某个容器 docker exec -it redis-1 /bin/sh # 创建集群 redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
# 进入集群 redis-cli -c # 查看集群信息 cluster info # 查看集群节点 cluster nodes # 在集群中设置某个值,例:a 的值为 b 127.0.0.1:6379> set a b -> Redirected to slot [15495] located at 172.38.0.13:6379 # 看到是在172.38.0.13上设置的,即redis-3上 # 在docker中停止第三个节点 docker stop redis-3 # 重新进入集群 redis-cli -c # 查看a的值 127.0.0.1:6379> get a -> Redirected to slot [15495] located at 172.38.0.14:6379 # 看到是在172.38.0.14返回的,即redis-4上 "b" # 这里测返回值的时候,要注意关闭的节点(新开的终端关闭了这个节点),关闭之后,需重新进入其他的节点,否则还是在这个节点中,因为被关闭了,所以响应不了
我们使用了docker之后,所有的技术都会慢慢的变得简单起来!
SpringBoot微服务打包Docker镜像
- 构建springboot项目
- 打包应用
- 编写dockerfile
- 构建镜像
- 发布运行
以后我们使用了Docker之后,给别人交付的就是一个镜像即可
到了这里我们已经完全够用了Docker!
预告:如果有很多镜像
企业实战
docker compose
docker swarm
CI/CD Jenkins 流水线!
更多推荐
所有评论(0)