# Docker学习与使用 **Published by:** [samehada](https://paragraph.com/@samehada/) **Published on:** 2023-03-20 **URL:** https://paragraph.com/@samehada/docker ## Content Docker—学习与应用1.Docker概述Docker是一种轻量级的容器化技术,可以将应用和其依赖项封装成一个可移植的容器,这使得在不同的环境中部署和运行应用程序变得更加容易。Docker容器技术的核心思想是隔离和打包装箱,每个容器是互相隔离的。 Docker诞生于2010年,最初是由一家名为dotCloud的公司开发的,该公司提供了一些pass的云计算服务。Docker最初并没有受到行业的关注,直到2013年它成为了开源项目,越来越多的人开始认识到它的优点,Docker也因此变得越来越流行。docker-logo与传统的虚拟机技术相比,Docker的优点在于轻量级、资源占用少、启动快速等方面。Docker容器化技术也是一种虚拟化技术,但与虚拟机不同的是,容器内的应用直接运行在宿主机的内核上,没有自己的内核和虚拟硬件,每个容器是互相隔离的,因此可以更快速地部署和运行应用程序。docker-structureDocker的作用在于实现DevOps,即开发和运维的快速协作,将应用程序的构建、测试、部署等过程自动化,提高效率和质量,降低成本。Docker提供了一整套的工具和服务,包括Docker引擎、Docker Hub、Docker Compose等,可以方便地管理和维护容器化应用程序。Docker是基于Golang开发的开源项目 官网地址:https://www.docker.com/ 文档地址:https://docs.docker.com/ 仓库地址:https://hub.docker.com2.Docker安装2.1 Docker的基本组成dockerDocker是一种轻量级容器技术,它的核心组成部分有镜像、容器和仓库。本文将在下面介绍这三个组成部分的概念和作用。镜像:镜像就像是一个模板,可以通过它来创建容器服务。例如,使用tomcat镜像可以创建一个tomcat01容器,容器中可以运行最终服务或项目。容器:容器则是通过镜像来创建的,利用容器技术独立运行一个或多个应用程序。启动、停止、删除等基本命令可以操作容器。可以把容器理解为一个简易的Linux系统。仓库:仓库是存放镜像的地方,分为公有仓库和私有仓库。DockerHub和阿里云都有容器服务器,可以配置镜像加速。通过使用Docker,可以方便地创建、部署和管理应用程序,加速开发和部署流程,提高开发效率和应用程序的可移植性。2.2 搭建Linux环境本文,笔者使用的是Unbuntu18.04版本的虚拟机,使用XShell连接工具对虚拟机进行操作,配置完成Linux环境后确保Xshell可以正常访问Ubuntu文件。ubuntu2.3 安装Docker首先需要先卸载掉Docker的旧版本文件数据。sudo apt-get remove docker docker-engine docker.io containerd runc 通过仓库的方式安装。 sudo apt-get update sudo apt-get install \ ca-certificates \ curl \ gnupg \ lsb-release 下面添加Docker的官方GPG key。 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 国内阿里云版 curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | apt-key add - 接下来验证key的指纹sudo apt-key fingerprint 0EBFCD88 正常的输出为:root@camile:/# sudo apt-key fingerprint 0EBFCD88 pub rsa4096 2017-02-22 [SCEA] 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88 uid [ 未知 ] Docker Release (CE deb) <docker@docker.com> sub rsa4096 2017-02-22 [S] 下面我们添加稳定版的docker仓库或者国内阿里云版本。# 官方版本 sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" # 国内阿里云版 sudo add-apt-repository \ "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \ $(lsb_release -cs) \ stable" 安装我们最新版本的docker ce和container。 sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io 查看我们安装的docker版本信息。docker --version 将非root用户加入docker组,以允许免sudo执行docker.sudo gpasswd -a 用户名 docker 重启服务并刷新docker组成员:sudo service docker restart newgrp - docker 设置开机自启动并启动 Docker-ce(安装成功后默认已设置并启动,可忽略)sudo systemctl enable docker sudo systemctl start docker 接下来我们安装docker-compose https://www.runoob.com/docker/docker-compose.htmlsudo curl -L https://github.com/docker/compose/releases/download/1.25.4/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose docker-compose --version 测试我们的第一个镜像hello-world。docker run hello-world hello-world卸载docker命令如下所示: sudo apt-get purge docker-ce docker-ce-cli containerd.io sudo rm -rf /var/lib/docker sudo rm -rf /var/lib/containerd 2.4 配置阿里云镜像加速器在阿里云上,提供了一些免费的容器镜像服务,我们找到控制台->左侧菜单->容器镜像服务->镜像加速器,其中Ubuntu配置镜像加速器的命令已给出:sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://alvnh3pv.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker 2.5 回顾上面我们运行了一个docker run的命令,笔者绘制了一个流程图供大家参考process那么Docker究竟是怎么工作的呢?这里笔者简单的介绍一下,Dcoker是一个 Client-Server结构的系统,Docker的守护进程运行在主机上,通过Socker从客户端访问。而DockerServer 接收到 Docker-Client 的指令,就会执行这个命令。如下所示工作方式3.Docker常用命令这一节,笔者总结了一些Docker的常用命令,速览以下有助于后续的使用。对于一些命令,笔者会在虚拟机上试验并给出响应结果。3.1 帮助命令docker version # 版本信息 docker info # 显示docker的系统信息,包括容器和镜像的信息 docker [命令] --help # 帮助文档,官网在 doc下的reference 下的 command-line reference 3.2 镜像命令docker images:查看本机所有的镜像root@camile:~# docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest feb5d9fea6a5 5 months ago 13.3kB # 解释 REPOSITORY:镜像的仓库源 TAG:镜像的标签 IMAGE ID:镜像的ID CREATED:镜像的创建时间 SIZE:镜像的大小 # 可选项 Options: -a, --all # 列出所有镜像 -f, --filter # 过滤镜像 -q, --quiet # 只显示镜像的id -aq # 列出所有镜像id **docker search:**搜索镜像root@camile:~# docker search mysql NAME DESCRIPTION STARS OFFICIAL AUTOMATED mysql/mysql-server Optimized MySQL Server Docker images. Create… 907 [OK] # 可选项 Options: -f=STARS=3000 --filter=STARS=3000 docker pull:下载镜像# 下载镜像 docker pull 镜像名[:tag] root@camile:~# docker pull mysql Using default tag: latest # 默认是最新版本 latest: Pulling from library/mysql 72a69066d2fe: Pull complete # 分层下载,docker image 的核心 联合文件系统 93619dbc5b36: Pull complete 99da31dd6142: Pull complete 626033c43d70: Pull complete 37d5d7efb64e: Pull complete ac563158d721: Pull complete d2ba16033dad: Pull complete 688ba7d5c01a: Pull complete 00e060b6d11d: Pull complete 1c04857f594f: Pull complete 4d7cfa90e6ea: Pull complete e0431212d27d: Pull complete Digest: sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709 #签名 Status: Downloaded newer image for mysql:latest docker.io/library/mysql:latest # 真实地址 # 等价于以下命令 docker pull docker.io/library/mysql:latest # 指定版本下载 root@camile:~# docker pull mysql:5.7 5.7: Pulling from library/mysql 72a69066d2fe: Already exists 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 imagesdocker rmi:删除镜像# 按照id删除镜像 docker rmi -f 容器id # 删除指定的镜像 docker rmi -f 容器id 容器id 容器id # 删除多个镜像 docker rmi -f $(docker images -aq) # 删除全部镜像 3.3 容器命令有了镜像,我们才可以创建容器,我们下载一个centos镜像来测试学习。新建容器并启动docker run [可选参数] image # 参数说明 --name=“Name” 容器名字 tomcat01 tomcat02 用来区分容器 -d 后台方式运行 -i -t -it 使用交互方式运行,进入容器查看内容 -p 指定容器的端口 -p 8080:8080 -p ip:主机端口:容器端口 -p 主机端口:容器端口(常用) -p 容器端口 容器端口 -p 随机指定端口 # 测试 root@camile:~# docker run -it centos /bin/bash # 启动容器并进入容器内部 [root@f2e7722031c0 /] # 进入容器内部 root@后面就是容器的id [root@f2e7722031c0 /]# ls # 查看容器内的centos目录 bin etc lib lost+found mnt proc run srv tmp var dev home lib64 media opt root sbin sys usr [root@f2e7722031c0 /]# exit # 从容器中退回主机 exit root@camile:~# 列出所有运行中的容器# docker ps 命令 # 列出当前正在运行的容器 -a # 列出当前正在进行的容器+带出历史运行的容器 -n=? # 显示最近几个创建的容器 -q # 只显示容器的ID root@camile:~# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f2e7722031c0 centos "/bin/bash" 4 hours ago Exited (0) 4 hours ago amazing_rosalind 退出容器 exit # 直接容器停止并退出 CTRL + P + Q # 容器不停止并tui'chu 删除容器docker rm 容器id # 删除指定的容器,不能删除正在运行的容器 docker rm -f $(docker ps -aq) # 删除所有的容器 docker ps -aq | xargs docker rm # 删除所有的容器 启动和停止容器的操作docker start 容器 id docker restart 容器id docker stop 容器id docker kill 容器id 3.4 其他命令后台启动容器# 命令 docker run -d 镜像名; root@camile:~# docker run -d centos # 问题 docker ps 发现,centos 停止了 # 常见的坑, docker 容器使用后台运行,就必须有一个前台进程,docker容器发现没有应用,就会自动停止 # 容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了 查看日志docker logs -f -t --tail 容器,没有日志 # 自己编写一段shell脚本 docker run -d centos /bin/bash -c "while true;do echo qiaowei;sleep 1;done" # 显示日志 root@camile:~# docker logs -tf --tail 10 397eabe2c023 2022-02-26T09:21:25.266776907Z qiaowei 2022-02-26T09:21:26.268727710Z qiaowei 2022-02-26T09:21:27.270738576Z qiaowei -tf # 显示日志 --tail # 显示日志条数 查看容器中的进程信息# 命令docker top 容器id root@camile:~# docker top 19334600a733 UID PID PPID C STIME TTY TIME CMD root 14960 14931 0 17:27 pts/0 00:00:00 /bin/bash 查看镜像的元数据# 命令 docker inspect 容器id 进入当前正在运行的容器# 我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置 # 命令 docker exec -it 容器id 路径 # 测试 root@camile:~# docker exec -it 19334600a733 /bin/bash [root@19334600a733 /]# ls bin etc lib lost+found mnt proc run srv tmp var dev home lib64 media opt root sbin sys usr [root@19334600a733 /]# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 09:27 pts/0 00:00:00 /bin/bash root 15 0 0 09:46 pts/1 00:00:00 /bin/bash root 31 15 0 09:46 pts/1 00:00:00 ps -ef # 方式二 docker attach 容器id root@camile:~# docker attach 19334600a733 [root@19334600a733 /]# ls bin etc lib lost+found mnt proc run srv tmp var dev home lib64 media opt root sbin sys usr # docker exec # 进入容器后开启一个新的终端,可以在里面操作(常用) # docker attach # 进入容器正在执行的终端,不会启动新的进程 从容器内拷贝文件到主机上docker cp 容器id:容器内路径 目前的主机路径 # 测试 [root@19334600a733 /]# cd /home [root@19334600a733 home]# ls [root@19334600a733 home]# touch test.java [root@19334600a733 home]# exit exit root@camile:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES root@camile:~# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 19334600a733 centos "/bin/bash" 32 minutes ago Exited (0) 12 seconds ago admiring_bohr 397eabe2c023 centos "/bin/bash -c 'while…" 39 minutes ago Exited (137) 37 minutes ago focused_ellis cd940d7abbb2 centos "/bin/bash -C 'while…" 40 minutes ago Exited (127) 40 minutes ago ecstatic_galileo 23db6f7950f8 centos "/bin/bash -C 'while…" 40 minutes ago Exited (127) 40 minutes ago keen_sanderson 8f9ce6c66f30 centos "/bin/bash" 43 minutes ago Exited (0) 40 minutes ago flamboyant_moser root@camile:~# docker cp 19334600a733:/home/test.java /home root@camile:~# cd home -bash: cd: home: No such file or directory root@camile:~# cd /home root@camile:/home# ls camile test.java # 拷贝是一个手动过程,未来我们使用 -v 卷的技术,可以实现 4.Docker部署简单环境接下来,笔者将带领大家安装Nginx和Tomcat这两个常见的镜像。4.1 安装Nginx# 1.搜索镜像 search 建议大家去docker搜索,可以看到帮助文档 # 2.下载nginx镜像 docker pull nginx # 3.运行测试 root@camile:/# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 605c77e624dd 8 weeks ago 141MB centos latest 5d0da3dc9764 5 months ago 231MB # -d 后台运行 # --name 给容器命名 # -p 宿主机端口:容器内端口 root@camile:/# docker run -d --name nginx01 -p 3344:80 nginx 586cda0f86a49f103522efcf0300a8592639ae2da23c8317745a487d8373a555 root@camile:/# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 586cda0f86a4 nginx "/docker-entrypoint.…" 4 seconds ago Up 4 seconds 0.0.0.0:3344->80/tcp, :::3344->80/tcp nginx01 root@camile:/# curl localhost:3344 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } 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> 4.2 部署Tomcat# 官方的使用 docker run -it --rm tomcat:9.0 # 我们之前的启动都是后台,停止了容器之后,容器还是可以查到,官方的方法一般是用完及删 # 我们的逻辑是先下载再启动 docker pull tomcat:9.0 # 启动运行 root@camile:/# docker run -d -p 3355:8080 --name tomcat01 tomcat # 发现问腿:1.Linux命令少了 2.没有webapps,阿里云镜像的原因,默认是最小的镜像,所有不必要的都删除吊 # 保证最小的运行环境 4.3 部署ES+kibana# es 暴露的端口很多! # es 十分的耗内存 # es 的数据一般需要放置在安全目录!挂载 # --net somenetwork ? 网络配置 # 启动 elasticsearch docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -e "discovery.type=single-node" elasticsearch:7.6.2 # 启动了 linux就卡住了 docker stats 查看 cpu状态 # es 是十分耗内存的 1核2G # 查看 docker stats # 测试以下 es 是否成功了 # 赶紧关闭,增加内存的限制 -e环境配置修改 docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:tag docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -e ES_JAVA_OPTS="-Xms64m -Xmx12m" elasticsearch:7.6.2 4.4 Docker可视化工具这里我们可以使用一个portainer,它是一个Docker的图形化界面管理工具,提供一个后台面板供我们操作,登陆进入可以管理我们的容器。docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portaioner 在虚拟机中可以使用:localhost:8080来访问界面portainer5.Docker镜像理解5.1 镜像是什么镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。 如何获得镜像:从远程仓库下载朋友拷贝自己制作一个镜像DockerFile5.2 镜像加载原理UnionFS(联合文件系统) 我们下载的时候看到的一层一层的数据就是这个。 UnionFS(联合文件系统):Union文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层地叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。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等标准目录和文件。各种不同的操作系统发行版,比如Ubuntu , Centos等等镜像分层平时我们安装虚拟机的CentOS都是好几个G,为什么Docker这里才200M?对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。因此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。5.3 分层理解分层的镜像我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层地在下载。下载时分层思考:为什么Docker镜像要采用这种分层结构? 最大的好处,我觉得莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。 查看镜像分层的方式可以通过docker image inspect命令![root@iZwz99sm8v95sckz8bd2c4Z ~]# docker image inspect nginx:latest [ { "Id": "sha256:ae2feff98a0cc5095d97c6c283dcd33090770c76d63877caa99aefbbe4343bdd", "RepoTags": [ "nginx:latest" ], "RepoDigests": [ "nginx@sha256:4cf620a5c81390ee209398ecc18e5fb9dd0f5155cd82adcbae532fec94006fb9" ], "Parent": "", "Comment": "", "Created": "2020-12-15T20:21:00.007674532Z", "Container": "4cc5da85f27ca0d200407f0593422676a3bab482227daee044d797d1798c96c9", "ContainerConfig": { "Hostname": "4cc5da85f27c", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "80/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "NGINX_VERSION=1.19.6", "NJS_VERSION=0.5.0", "PKG_RELEASE=1~buster" ], "Cmd": [ "/bin/sh", "-c", "#(nop) ", "CMD [\"nginx\" \"-g\" \"daemon off;\"]" ], "Image": "sha256:13bffe371b56f4aeed88218ec17d0c6f653a83b49bd3e211fc8cfa2ca5d7a3d3", "Volumes": null, "WorkingDir": "", "Entrypoint": [ "/docker-entrypoint.sh" ], "OnBuild": null, "Labels": { "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>" }, "StopSignal": "SIGQUIT" }, "DockerVersion": "19.03.12", "Author": "", "Config": { "Hostname": "", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "80/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "NGINX_VERSION=1.19.6", "NJS_VERSION=0.5.0", "PKG_RELEASE=1~buster" ], "Cmd": [ "nginx", "-g", "daemon off;" ], "Image": "sha256:13bffe371b56f4aeed88218ec17d0c6f653a83b49bd3e211fc8cfa2ca5d7a3d3", "Volumes": null, "WorkingDir": "", "Entrypoint": [ "/docker-entrypoint.sh" ], "OnBuild": null, "Labels": { "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>" }, "StopSignal": "SIGQUIT" }, "Architecture": "amd64", "Os": "linux", "Size": 132935043, "VirtualSize": 132935043, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/cb791e78a08db7091bf2ce1d78603f1758f52199e57f1805156fe30e39067aae/diff:/var/lib/docker/overlay2/1e73a72b25af68ee9abf4eb443f778d31226e12e9af428fcc14c7b044c83b258/diff:/var/lib/docker/overlay2/88c9c01762f2af8327db65d0b0d4a64785e87c9c2ab76c62e7d03619db03a985/diff:/var/lib/docker/overlay2/7304ab112ac4a9cb91fc6f74730be28fecbe19f042e92d321aa9181424cc4b2e/diff", "MergedDir": "/var/lib/docker/overlay2/48b288740bbb2b07b41ed43a4d17a005c46b08d3357d2960b5ef7db4b2de6618/merged", "UpperDir": "/var/lib/docker/overlay2/48b288740bbb2b07b41ed43a4d17a005c46b08d3357d2960b5ef7db4b2de6618/diff", "WorkDir": "/var/lib/docker/overlay2/48b288740bbb2b07b41ed43a4d17a005c46b08d3357d2960b5ef7db4b2de6618/work" }, "Name": "overlay2" }, "RootFS": { "Type": "layers", "Layers": [ "sha256:87c8a1d8f54f3aa4e05569e8919397b65056aa71cdf48b7f061432c98475eee9", "sha256:5c4e5adc71a82a96f02632433de31c998c5a9e2fccdcbaee780ae83158fac4fa", "sha256:7d2b207c26790f693ab1942bbe26af8e2b6a14248969e542416155a912fec30d", "sha256:2c7498eef94aef8c40d106f3e42f7da62b3eee8fd36012bf7379becc4cd639a2", "sha256:4eaf0ea085df254fd5d2beba4e2c11db70a620dfa411a8ad44149e26428caee4" ] }, "Metadata": { "LastTagTime": "0001-01-01T00:00:00Z" } } ] 这里指示了分层信息:"RootFS": { "Type": "layers", "Layers": [ "sha256:87c8a1d8f54f3aa4e05569e8919397b65056aa71cdf48b7f061432c98475eee9", "sha256:5c4e5adc71a82a96f02632433de31c998c5a9e2fccdcbaee780ae83158fac4fa", "sha256:7d2b207c26790f693ab1942bbe26af8e2b6a14248969e542416155a912fec30d", "sha256:2c7498eef94aef8c40d106f3e42f7da62b3eee8fd36012bf7379becc4cd639a2", "sha256:4eaf0ea085df254fd5d2beba4e2c11db70a620dfa411a8ad44149e26428caee4" ] }, 所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。 举一个简单的例子,假如基于Ubuntu Linux 16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。 该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。3个镜像层在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个层包含3个文件,而镜像包含了来自两个镜像层的6个文件。6个文件这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。 Linux上可用的存储引擎有AUFS、Overlay2、Device Mapper、Btrfs以及ZFS。顾名思义,每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。 Docker在Windows 上仅支持windowsfilter一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW[1].下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。特点 Docker镜像都是只读地,当容器启动时,一个新的可写层被加载到镜像的顶部! 这一层就是我们通常说的容器层,容器之下的都是镜像层!5.4 commit镜像当我们想要保存当前容器的状态,就可以通过commit来提交,获得一个镜像:docker commit 提交容器成为一个新的副本 docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[tag] 实战测试# 启动一个默认的tomcat # 发现这个默认的 tomcat 没有webapps应用,镜像的原因,官方的镜像默认 webapps 下是没有文件的 # 自己拷贝进去基本的文件 # 将我们操作过的容器通过commit提交为一个镜像!我们以后就可以使用我们修改过的镜像即可,这也就是我们自己的一个修改镜像。 6.Docker容器数据卷6.1 什么是容器数据卷容器数据卷是Docker中一种用于持久化数据的技术,它可以让容器中的数据在容器删除后不会丢失。Docker的理念是将应用和环境打包成一个镜像,但如果数据都在容器中,那么容器删除后数据也会消失。因此,需要使用数据卷技术实现数据持久化和同步操作。挂载例如,在使用MySQL时,如果容器删除,则数据库中的数据也会丢失,因此需要将MySQL数据存储在本地并使用卷技术实现容器和本地数据的同步。卷技术通过目录挂载实现,将容器内的目录挂载到Linux系统上。因此,容器间也可以共享数据,实现数据共享。容器数据卷是Docker中非常重要的一部分,可以实现容器的持久化和同步操作,为容器应用提供了强大的数据管理功能。6.2 使用数据卷方式一:直接使用命令来挂载 -v docker run -it -v 主机目录:容器目录 # 测试 docker run -it -v /home/ceshi:/home centos /bin/bash # 容器起来时候我们可以通过 docker inspect 容器id 来查看挂载状态 挂载状态在容器内简历一个test.java测试文件。测试文件的同步,是一个双向绑定的过程。双向绑定6.3 实战:安装MySQL# 获取镜像 camile@camile:/$ docker pull mysql:5.7 # 运行容器,需要做数据卷挂载 # 安装启动mysql -e表示配置环境 # 官方测试:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag # 启动我们的mysql -d 后台运行 -p 端口映射 -v 卷挂载 -n 容器名字 camile@camile:~$ docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=zuiweizhiming666 --name mysql01 mysql:5.7 # 启动成功之后,我们在本地使用 navicat 来测试以下 # navicat 连接到服务器的3310 -3310和容器内的3306映射,这个时候我们就可以连接上了 # 在本地测试创建一个数据库,查看一下我们创建的路径是否ok testtest6.4 具名和匿名挂载Docker中的匿名挂载和具名挂载是两种不同的数据卷挂载方式。 匿名挂载是指在启动容器时,只指定容器内的路径,而不指定宿主机的目录。这样会生成一个随机的宿主机挂载目录,可以通过 docker volume ls 命令查看。 具名挂载是指在启动容器时,既指定容器内的路径,又指定一个卷名作为宿主机的目录。 这样可以方便地找到和管理数据卷,也可以通过 docker volume inspect 卷名 命令查看详细信息。 匿名挂载和具名挂载的语法如下:-v 容器内路径 # 匿名挂载-v 卷名:容器内路径 # 具名挂载下面是具名挂载和匿名挂载的相关命令代码块:# 启动一个nginx容器,使用匿名挂载,将容器内的/etc/nginx目录挂载到宿主机上 docker run -d -P --name nginx01 -v /etc/nginx nginx # 查看所有的数据卷 docker volume ls # 启动一个nginx容器,使用具名挂载,将容器内的/etc/nginx目录挂载到宿主机上,并命名为juming-nginx docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx # 查看具体的数据卷信息 docker volume inspect juming-nginx 6.5 DockerFileDockerFile 就是用来构建Docker镜像的构建文件、命令脚本,下面先体验一下! 通过这个脚本可以生成镜像,镜像是一层一层的,脚本是一个个的命令。# 创建一个DockerFile文件,名字可以随机 ,建议 Dockerfile # 文件中的内容 FROM centos VOLUME ["volume01","volume02"] CMD echo "---end---" CMD /bin/bash # 这里的每个命令,就是镜像的一层 # 启动自己写的容器 这个目录就是我们生成镜像的时候自动挂载的数据卷目录。这个卷和外部一定有一个同步的目录。查看一下卷挂载的路径。 测试一下刚才的文件是否同步了。这种方式我们未来使用的十分多,因为我们通常会构建自己的镜像!假设构建镜像的时候没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径。7.DockerFile7.1 DockerFiledockerFile 是用来docker镜像的文件,是命令参数脚本。 构建步骤:编写一个dockerfile文件docker build 构建成一个镜像docker run 运行镜像docker push 发布镜像7.2 dockerFile构建过程基础知识:每个保留关键字都是大写字母执行从上到下执行#表示注释每一个指令都会创建提交一个新的镜像层,并提交!dockerfiledockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单。 Docker镜像逐渐成为企业交付的标准,必须要掌握。 步骤: DockerFile:构建文件,定义了一切的步骤,源代码 DockerImages:DockerFile构建生成的镜像,最终发布和运行的产品,原来是 jar war。 Docker容器:容器就是镜像运行起来提供服务的。7.3 DockerFile指令知晓了DockerFile命令,我们就可以自己制作镜像:FROM # 基础镜像,一切从这里开始构建 MANITAINER # 镜像是谁写的 姓名+邮箱 RUN # 镜像构建的时候需要运行的命令 ADD # 步骤,tomcat镜像,这个tomcat压缩包!添加内容 WORKDIR # 镜像的工作目录 VOLUME # 挂载的目录 EXPOSE # 指定暴露端口 CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代 ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令 ONBUILD # 当个构建一个被继承dockerfile 的时候,会运行这个指令,触发指令 COPY # 类似ADD,将我们文件拷贝到镜像中 ENV # 构建的时候设置环境变量 7.4 实战测试Docker Hub 中绝大多数镜像都是从这个基础镜像过来的 FROM scratch,然后配置需要的软件和配置来进行的构建。创建一个自己的Centos# 1.编写DockerFile的文件 FROM centos:7 MAINTAINER qiaowei<454921269@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] Successfully built 11a9535c2896 Successfully tagged mycentos:0.1 # 3.测试运行 root@camile:/home/dockerfile# docker run -it 11a9535c2896 [root@f9c5dbcee829 local]# pwd /usr/local [root@f9c5dbcee829 local]# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.6 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:ac:11:00:06 txqueuelen 0 (Ethernet) RX packets 23 bytes 2804 (2.7 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 [root@f9c5dbcee829 local]# vim test 自己写的centos 添加了vim 和 net-tools ,测试成功! 我们可以列出本地镜像的变更历史root@camile:/home/dockerfile# docker history 11a9535c2896 IMAGE CREATED CREATED BY SIZE COMMENT 11a9535c2896 4 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/bin… 0B 5005cf751c81 4 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B 21407997234d 4 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B a567cd94200e 4 minutes ago /bin/sh -c #(nop) EXPOSE 80 0B 48ad5b128e9a 4 minutes ago /bin/sh -c yum -y install net-tools 161MB da7d8a18d88e 4 minutes ago /bin/sh -c yum -y install vim 216MB b1524097a173 4 minutes ago /bin/sh -c #(nop) WORKDIR /usr/local 0B 01282534605d 4 minutes ago /bin/sh -c #(nop) ENV MYPATH=/usr/local 0B 9bb0de5c2898 4 minutes ago /bin/sh -c #(nop) MAINTAINER qiaowei<454921… 0B eeb6ee3f44bd 5 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 5 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B 7.5 tomcat镜像准备镜像文件 tomcat 压缩包,jdk的压缩包。jdk编写dockerfile文件,官方命名“Dockerfile”,build会自动寻找这个文件,就不需要 -f 指定了。root@camile:/home/qiaowei/build/tomcat# touch readme.txt root@camile:/home/qiaowei/build/tomcat# vim Dockerfile # 自己制作Dockerfile FROM centos:7 MAINTAINER qiaowei<454921269@qq.com> COPY readme.txt /usr/local/readme.txt ADD jdk-17_linux-x64_bin.tar.gz /usr/local/ ADD apache-tomcat-9.0.59.tar.gz /usr/local/ RUN yum -y install vim ENV MYPATH /usr/local WORKDIR $MYPATH ENV JAVA_HOME /usr/local/jdk-17.0.2 ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.59 ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.59 ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin EXPOSE 8080 CMD /usr/local/apache-tomcat-9.0.59/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.59/bin.logs/catalina.out 构建镜像# docker build -t diytomcat . 构建镜像1.运行容器:docker run -d -p 9090:8080 --name qiaoweitomcat -v /home/qiaowei/build/tomcat/test:/usr/local/apache-tomcat-9.0.59/webapps/test -v /home/qiaowei/build/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.59/logs diytomcat 访问测试tomcat发布项目(由于做了卷挂载,我们直接在本地编写项目就可以)<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> </web-app> 随便写一个html文件,测试访问<!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <title>这是个标题</title> </head> <body> <h1>这是一个一个简单的HTML</h1> <p>Hello World!</p> </body> </html> html7.6 发布自己的镜像Dockerhub地址:https://hub.docker.com/,注册自己的账号确定这个账号可以登录在我们服务器上提交自己的镜像Usage: docker login [OPTIONS] [SERVER] Log in to a Docker registry. If no server is specified, the default is defined by the daemon. Options: -p, --password string Password --password-stdin Take the password from stdin -u, --username string Username 登录完毕后可以提交镜像了# 先给镜像打一个标签 docker tag 1ba62e6aa598 wulegekong/tomcat:1.0 # 提交镜像 docker push wulegekong/tomcat:1.0 # 注意:镜像名前一定是自己dockerhub的用户名,否则会拒绝push请求 7.7 发布镜像到阿里云容器服务登录阿里云找到容器镜像服务创建命名空间根据官方提供的操作指南操作即可。8.Docker网络我们使用 ip addr 命令查看本机的所有网络信息:ip addr这里出现了docker0地址,下面简单理解一下docker网络的原理:我们每安装一个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中的所有的网络接口都是虚拟的,虚拟的转发效率高,只要容器删除,对应网桥一对就没了。9.总结笔者仅仅简单地学习和应用了Docker的一些基本内容,勉强算是入门,后续会学习Docker-Compose等进阶内容,敬请期待。 ## Publication Information - [samehada](https://paragraph.com/@samehada/): Publication homepage - [All Posts](https://paragraph.com/@samehada/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@samehada): Subscribe to updates