Docker

简介

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 LinuxWindows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。

Docker是基于 Go 语言开发的,是一个开源项目。

文档地址:https://docs.docker.com/

仓库地址:https://hub.docker.com/

虚拟机技术缺点:模拟一个完整的操作系统,资源占用多,步骤冗余,启动慢。

Docker 容器化技术:不是模拟的一个完整的操作系统。运行在宿主机的内核上。每个容器内是互相隔离的,互不影响。

DevOps:开发 运维。

应用更快的交付和部署。

传统:安装各种的jar包,打包发布。

Docker :一键打包镜像发布,测试。

更便捷的升级和扩缩容,项目打包为一个镜像,部署应用就和搭积木一样。

更简单的系统运维,容器化后,开发测试环境都是一致的。

更高效的计算资源利用,Docke是内核级的虚拟化,在一个物理机上可以运行很多的容器。

Docker安装

Docker的基本组成

镜像(image):

就好比是一个模板,可通过这个镜像来创建容器服务,比如 tomcat 镜像--->run--->tomcat01容器,通过这个镜像可以创建多个容器(应用最终在容器中运行)。

容器(container):

Docker利用容器技术,独立运行一个或一组应用,通过镜像创建。

启动,停止,删除,基本命令。

仓库(repository):

存放镜像的地方。仓库分为公有仓库和私有仓库。

安装Docker

环境准备:

  1. 需要会Linux基础
  2. Centos7
  3. 使用Xshell连接远程服务器操作
  4. 已经购买云服务器(以下使用阿里云)

环境查看

#系统内核是3.0以上的
[root@zhourui /]# uname -r
4.18.0-193.28.1.el8_2.x86_64
#系统版本
[root@zhourui /]# cat /etc/os-release
NAME="CentOS Linux"
VERSION="8 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="8"
PLATFORM_ID="platform:el8"
PRETTY_NAME="CentOS Linux 8 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:8"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/" CENTOS_MANTISBT_PROJECT="CentOS-8"
CENTOS_MANTISBT_PROJECT_VERSION="8"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="8"

安装:参考帮助文档 https://docs.docker.com/engine/install/centos/

卸载旧的版本

#卸载
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine #需要的安装包
yum install -y yum-utils
#设置镜像的仓库
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo #默认的是国外的十分慢
#阿里云镜像 (推荐使用)
yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #更新yum软件包索引
yun makecache fast #安装docker decker-ce社区版的 ee企业版
yum install docker-ce docker-ce-cli containerd.io #启动docker
systemctl start docker #查看是否安装成功
docker version

#启动 hello-world
docker run hello-world

#查看下载的hello-world镜像
[root@zhourui /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 2 weeks ago 13.3kB
#卸载docker
yum remove docker-ce docker-ce-cli containerd.io
#删除资源
rm -rf /var/lib/docker
rm -rf /var/lib/containerd

配置阿里云镜像加速

登录阿里云找到容器服务。

找到容器镜像服务

配置使用

sudo mkdir -p /etc/docker

sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://tk46rux4.mirror.aliyuncs.com"]
}
EOF sudo systemctl daemon-reload sudo systemctl restart docker

回顾helloworld流程

流程图

工作原理

Docker是一个Client,Server结构的系统,Docker的守护进程运行在主机上,通过Socket从客户端访问。

DockerServer接收到DockerClient的指令,就会执行这个命令。

Docker为什么比VNM快:

Docker有比虚拟机更少的抽象层。

Docker利用的是宿主机的内核,VM有自己的Guest OS。

新建一个容器的时候,Docker不需要像虚拟机一样新建一个系统内核。利用宿主机的内核,提升了启动速度和系统资源利用率。

Docker的常用命令

帮助命令

docker -version    #显示docker的版本信息
docker info #docker的详细信息 镜像和容器的数量
docker 命令 --help #万能命令
docker --help #docker的所有命令

命令:官网地址 https://docs.docker.com/reference/

镜像命令

docker images:查看本机所有镜像

[root@zhourui /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 2 weeks ago 13.3kB #解释
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的 id
CREATED 镜像的创建时间
SIZE 镜像的大小 #可选项
-a, --all #显示所有的镜像
-q, --quiet #只显示镜像的id

docker search:搜索镜像

[root@zhourui /]# docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 10634 [OK]
mariadb MariaDB Server is a high performing open sou… 3990 [OK] #可选项
--filter=STARS=3000 #搜索出来的就是stars大于等于3000的 -f简写
[root@zhourui /]# docker search mysql -f=STARS=3000
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 10634 [OK]
mariadb MariaDB Server is a high performing open sou… 3990 [OK]

docker pull:下载镜像

#下载 docker pull 镜像名 [:tag](可以选版本) 不写版本默认latest最后一个
[root@zhourui /]# docker pull mysql
Using default tag: latest
latest: Pulling from library/mysql
a076a628af6f: Pull complete #分层下载 docker image核心 联合文件系统
f6c208f3f991: Pull complete
88a9455a9165: Pull complete
406c9b8427c6: Pull complete
7c88599c0b25: Pull complete
25b5c6debdaf: Pull complete
43a5816f1617: Pull complete
1a8c919e89bf: Pull complete
9f3cf4bd1a07: Pull complete
80539cea118d: Pull complete
201b3cad54ce: Pull complete
944ba37e1c06: Pull complete
Digest: sha256:feada149cb8ff54eade1336da7c1d080c4a1c7ed82b5e320efb5beebed85ae8c #签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest #真实地址 # docker pull mysql
# 等价
# docker pull docker.io/library/mysql:latest #指定版本下载
[root@zhourui /]# docker pull mysql:5.7
5.7: Pulling from library/mysql
a076a628af6f: Already exists #共用
f6c208f3f991: Already exists
88a9455a9165: Already exists
406c9b8427c6: Already exists
7c88599c0b25: Already exists
25b5c6debdaf: Already exists
43a5816f1617: Already exists
1831ac1245f4: Pull complete
37677b8c1f79: Pull complete
27e4ac3b0f6e: Pull complete
7227baa8c445: Pull complete
Digest: sha256:b3d1eff023f698cd433695c9506171f0d08a8f92a0c8063c1a4d9db9a55808df
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7 [root@zhourui /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 2 weeks ago 13.3kB
mysql 5.7 a70d36bc331a 2 months ago 449MB
mysql latest c8562eaf9d81 2 months ago 546MB

docker rmi:删除镜像

#删除指定的容器 根据id
[root@zhourui /]# docker rmi -f c8562eaf9d81
#删除多个镜像
[root@zhourui /]# docker rmi -f id1 id2 id3
#删除全部容器
[root@zhourui /]# docker rmi -f $(docker images -aq)

容器命令

我们有了镜像才可以创建容器,下载一个CentOS镜像来测试学习。

docker pull centos

新建容器并启动

docker run (可选参数) image

#参数说明
--name=“Name” #容器名字 tomcat01 tomcat01 来区分
-d #后台方式运行
-it #使用交互方式运行,进入容器查看内容
-p #指定容器的端口 -p 8080:8080
-p 主机端口:容器端口 (常用)
-p ip:主机端口:容器端口
-p 容器端口
容器端口(不写-p)
-p #随机指定端口 #启动并进入容器
[root@zhourui /]# docker run -it centos /bin/bash
[root@b728c79b5448 /]# ls #查看容器内的centos 基础版本 很多的命令不完善
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@b728c79b5448 /]# exit #退出命令
exit
[root@zhourui /]# ls
bin boot dev etc home lib lib64 media mnt opt patch proc root run sbin srv sys tmp usr var www

列出所有运行的容器

# docker ps
#列出所有在运行的容器
-a #列出历史运行过的容器
-n=? #显示最近创建的n个容器
-q #列出运行容器的id [root@zhourui /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@zhourui /]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b728c79b5448 centos "/bin/bash" 4 minutes ago Exited (0) 2 minutes ago relaxed_elbakyan
0ce52f9209e4 d1165f221234 "/hello" 5 hours ago Exited (0) 5 hours ago intelligent_mirzakhani

退出容器

exit  #容器停止并退出
ctrl +P +Q #按住这三个键 容器不停止退出 [root@zhourui /]# docker run -it centos /bin/bash
[root@c9797d0b4ba8 /]# [root@zhourui /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c9797d0b4ba8 centos "/bin/bash" About a minute ago Up About a minute inspiring_faraday

删除容器

docker rm 			#删指定id的容器  不能删除正在运行的容器  强制删除 rm -f
docker rm -f $(docker ps -aq) #删除全部的容器
docker -a-q|xargs docker rm #删除全部容器

启动和停止容器的操作

docker start 容器id 		#启动
docker restart 容器id #重启
docker stop 容器id #停止容器
docker kill 容器id #强制停止

常用其它命令

后台启动容器

# docker run -d 容器名  后台启动
[root@zhourui /]# docker run -d centos
#运行docker ps 发现centos停止了 #docker容器使用后台运行,就必须有一个前台进程,docker发现没有应用,就会自动停止

查看日志

docker logs -f -t --tail 10 容器id #打印最近10条日志

#编写shell脚本
“while true;do echo zhourrrrr;sleep 1;done” [root@zhourui /]# docker run -d centos /bin/bash -c "while true;do echo zhourrrr;sleep 1;done"
e79bac46e660abb781dcce7b0dbd3a3a896b573a104fdd9a15db0bbf5331341b
[root@zhourui /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e79bac46e660 centos "/bin/bash -c 'while…" 3 seconds ago Up 1 second jolly_sanderson #显示日志
-tf #显示日志 t 时间
--tail number #最近的多少条数据
[root@zhourui /]# docker logs -f -t --tail 10 e79bac46e660

查看容器中的进程信息

docker top 容器id

[root@zhourui /]# docker top e79bac46e660
UID PID PPID C STIME TTY
root 227610 227588 0 22:36 ?
root 229020 227610 0 22:45 ?

查看镜像源数据

docker inspect 容器id

[root@zhourui /]# docker inspect e79bac46e660
[
{
"Id": "e79bac46e660abb781dcce7b0dbd3a3a896b573a104fdd9a15db0bbf5331341b",
"Created": "2021-03-21T14:36:07.740342428Z",
"Path": "/bin/bash",
"Args": [
"-c",
"while true;do echo zhourrrr;sleep 1;done"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 227610,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-03-21T14:36:08.2053845Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
.........#省略...
}
}

进入当前正在运行的容器

#通常容器都是后台的方式运行的,需要进入容器修改一些配置
#命令
docker exec -it 容器id bashShell(bin/bash)
#测试
[root@zhourui /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
538cddb5e369 centos "bin/bash -c 'while …" 14 seconds ago Up 13 seconds quizzical_wing
[root@zhourui /]# docker exec -it 538cddb5e369 bin/bash
[root@538cddb5e369 /]#
[root@538cddb5e369 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@538cddb5e369 /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 11:08 ? 00:00:00 bin/bash -c while true;do echo zzzzzrr;sleep 2;done
root 66 0 0 11:10 pts/0 00:00:00 bin/bash
root 131 1 0 11:12 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 2
root 132 66 0 11:12 pts/0 00:00:00 ps -ef #方式二
docker attach 容器id
#测试
[root@zhourui /]# docker attach 538cddb5e369
zzzzzrr
zzzzzrr
zzzzzrr
zzzzzrr
#进去后是正在执行的当前代码,想停止可以新开一个窗口 docker rm -f $(docker ps -aq) # docker exec 进入后打开了一个新的终端,可以在里面操作
# docker attach 进入容器正在执行的终端,不会启动新的进程

从容器内拷贝文件到主机上

docker cp 容器id:容器内路径 目的主机路径
#测试
[root@zhourui /]# cd /home
[root@zhourui home]# ls
www zhour.java
[root@zhourui home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
44e87620bf99 centos "/bin/bash" About a minute ago Up About a minute romantic_burnell
#进入容器
[root@zhourui home]# docker attach 44e87620bf99
[root@44e87620bf99 /]# cd /home
[root@44e87620bf99 home]# ls
#在容器内新建一个文件
[root@44e87620bf99 home]# touch zr.java
[root@44e87620bf99 home]# ls
zr.java
[root@44e87620bf99 home]# exit
exit
[root@zhourui home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@zhourui home]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
44e87620bf99 centos "/bin/bash" 3 minutes ago Exited (0) 6 seconds ago romantic_burnell #将容器内的文件拷贝到主机上
[root@zhourui home]# docker cp 44e87620bf99:/home/zr.java /home
[root@zhourui home]# ls
www zhour.java zr.java
[root@zhourui home]# #拷贝是一个手动过程,后面学习使用 -v 卷的技术,可以实现自动同步

小结

常用命令

练习部署

部署Nginx

  1. 搜索镜像:docker search nginx

  2. 下载镜像:docker pull nginx

  3. 运行测试:docker run -d --name nginx01 -p 3344:80 nginx (--name:起别名,-p 3344:80 3344是暴露的端口就是宿主机端口 80是nginx默认端口就是容器的端口)

    [root@zhourui home]# docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    nginx latest f6d0b4767a6c 2 months ago 133MB
    centos latest 300e315adb2f 3 months ago 209MB
    hello-world latest bf756fb1ae65 14 months ago 13.3kB #--name:起别名,-p 3344:80 3344是暴露的端口 80是nginx默认端口
    [root@zhourui home]# docker run -d --name nginx01 -p 3344:80 nginx
    56b36ad955ca7cf6d80708b20d7ffd1152a0ca974c312df45bfe9e31d0888e0b
    [root@zhourui home]# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    56b36ad955ca nginx "/docker-entrypoint.…" 7 seconds ago Up 6 seconds 0.0.0.0:3344->80/tcp nginx01
    [root@zhourui home]# curl localhost:3344 [root@zhourui home]# docker exec -it nginx01 bin/bash
    root@56b36ad955ca:/# whereis nginx
    nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
    root@56b36ad955ca:/# cd /etc/nginx
    root@56b36ad955ca:/etc/nginx# ls
    conf.d fastcgi_params koi-utf koi-win mime.types modules nginx.conf scgi_params uwsgi_params win-utf
    root@56b36ad955ca:/etc/nginx#
    #每次改动nginx的配置文件,都需要进入容器的内部修改,非常麻烦,后面学习数据卷的技术就可以在容器外部修改文件,容器内自动同步。

    访问自己服务器的nginx:http://39.105.48.232:3344/(前提是自己阿里云服务器安全组中开启了3344端口)

部署Tomcat

#docker hub 官方的使用
docker run -it --rm tomcat:9.0
#之前练习的启动在后台,停止容器后,容器还在,可以查到。run -it --rm 一般用来测试,用完即删除(容器删除镜像还在)
[root@zhourui /]# docker pull tomcat [root@zhourui /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat 9.0 040bdb29ab37 2 months ago 649MB
tomcat latest 040bdb29ab37 2 months ago 649MB
nginx latest f6d0b4767a6c 2 months ago 133MB
centos latest 300e315adb2f 3 months ago 209MB
hello-world latest bf756fb1ae65 14 months ago 13.3kB
[root@zhourui /]# docker run -d -p 3355:8080 --name tomcat01 tomcat
53197d7745a2d7f83f3a45b1f474a189eb7f496b0cf08c9a509a6c390680e347
[root@zhourui /]# curl localhost:3355

浏览器测试访问:http://39.105.48.232:3355/(阿里云安全组开启端口),可以访问但是显示404。

#进入容器
[root@zhourui /]# docker exec -it tomcat01 /bin/bash
root@53197d7745a2:/usr/local/tomcat# ls
BUILDING.txt CONTRIBUTING.md LICENSE NOTICE README.md RELEASE-NOTES RUNNING.txt bin conf lib logs native-jni-lib temp webapps webapps.dist work
root@53197d7745a2:/usr/local/tomcat# cd webapps
root@53197d7745a2:/usr/local/tomcat/webapps# ls
root@53197d7745a2:/usr/local/tomcat/webapps#
#发现ll无法使用,ls-al可以使用,命令少了。webapps中是空的,默认的是最小的镜像,不必要的被删除了,保证的是最小可用环境。

如果想要访问,可以复制webapps.dist目录的内容到webapps中

root@53197d7745a2:/usr/local/tomcat/webapps# cd ..
root@53197d7745a2:/usr/local/tomcat# cd webapps.dist
root@53197d7745a2:/usr/local/tomcat/webapps.dist# ls
ROOT docs examples host-manager manager
root@53197d7745a2:/usr/local/tomcat/webapps.dist# cd ..
root@53197d7745a2:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@53197d7745a2:/usr/local/tomcat# cd webapps
root@53197d7745a2:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
root@53197d7745a2:/usr/local/tomcat/webapps#

再次刷新网页访问即可!

部署es+kibana

#es暴漏的端口十分多
#es十分耗内存
#es的数据一般需要放置到安全目录,挂载。
#--net somenetwork 网络配置 #启动(启动前停掉其它的容器,防止启动不了)
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2 #docker stats 容器id 查看cpu的状态
#启动后 发现执行docker ps命令非常卡,因为内存快耗尽。

启动后可以从宝塔上看到自己服务器的内存状态。(也可以使用命令docker stats 容器id 查看cpu,内存的状态)

停掉es

[root@zhourui /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
94c6cad2a01d elasticsearch:7.6.2 "/usr/local/bin/dock…" 5 minutes ago Up 5 minutes 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp elasticsearch
[root@zhourui /]# docker stop 94c6cad2a01d
94c6cad2a01d

这时查看服务器的状态

再次启动,增加内存的配置,修改配置文件,-e 环境配置修改。

docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node"  -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2

可视化

  • portainer(图形化界面管理工具,提供一个面板供操作)
docker run -d -p 9222:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
  • Rancher(CI/CD 持续集成/持续部署时使用)

启动portainer后访问测试:http://39.105.48.232:9222/,密码可以随意输入。

进入后选择local,点击connect

可以看到镜像,容器等

查看镜像

Docker镜像

镜像是什么:镜像是一种轻量级的,可执行的独立软件包。用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码,运行时,库,环境变量和配置文件。

将应用直接打包为docker镜像,就可以直接跑起来。

如何得到镜像:

  • 从仓库下载
  • 自己制作一个镜像

Docker镜像加载原理

UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层,轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同的目录挂载到同一个虚拟文件系统下。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就是各种不同的操作系统发行版,比如Ubantu,Centos等。

可以使用docker images看到Centos的镜像非常小。

对于一个精简的OS,rootfs可以很小,只需包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需提供rootfs就可以了,因此可见对于不同的Linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以共用bootfs。

分层理解

下载一个镜像,观察日志输出,可以看到是一层一层的在下载(分层下载,提高了复用性)

使用docker inspect redis,可以看到RootFS

 "RootFS": {
"Type": "layers",
"Layers": [
"sha256:cb42413394c4059335228c137fe884ff3ab8946a014014309676c25e3ac86864",
"sha256:8e14cb7841faede6e42ab797f915c329c22f3b39026f8338c4c75de26e5d4e82",
"sha256:1450b8f0019c829e638ab5c1f3c2674d117517669e41dd2d0409a668e0807e96",
"sha256:f927192cc30cb53065dc266f78ff12dc06651d6eb84088e82be2d98ac47d42a0",
"sha256:a24a292d018421783c491bc72f6601908cb844b17427bac92f0a22f5fd809665",
"sha256:3480f9cdd491225670e9899786128ffe47054b0a5d54c48f6b10623d2f340632"
]
},

理解:所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,都会在当前的镜像层上,创建新的镜像层。在添加额外的镜像层时,镜像始终保持是当前所有镜像的组合。

特点:

docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常是我们所说的容器层,容器之下都是镜像层。

commit镜像

docker commit #提交容器成为一个新的副本
#命令和git类似
docker commit -m=“提交描述信息” -a=“作者” 容器id 目标镜像名:[TAG]

测试

#启动一个tomcat
docker run -it -p 8081:8080 tomcat #在新的窗口进入tomcat
[root@zhourui /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS 1fd9b7b4cb3d tomcat "catalina.sh run" 28 seconds ago Up 27 seconds 0.0.0.0:8081->8080/tcp
[root@zhourui /]# docker exec -it 1fd9b7b4cb3d /bin/bash #官方默认的tomcat的webapps下面没有应用,自己拷贝
cp -r webapps.dist/* webapps #提交自己的镜像,以后使用修改过的镜像即可
[root@zhourui /]# docker commit -a="zhourr" -m="add webapps" 1fd9b7b4cb3d tomcat02:1.0
sha256:1c7804b415ba38099178f63e48444aebec938252632defd16bb35acc71bdabab
[root@zhourui /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat02 1.0 1c7804b415ba 6 seconds ago 654MB
redis latest 621ceef7494a 2 months ago 104MB
tomcat 9.0 040bdb29ab37 2 months ago 649MB
tomcat latest 040bdb29ab37 2 months ago 649MB
nginx latest f6d0b4767a6c 2 months ago 133MB
centos latest 300e315adb2f 3 months ago 209MB
portainer/portainer latest 62771b0b9b09 8 months ago 79.1MB
elasticsearch 7.6.2 f29a1ee41030 12 months ago 791MB
hello-world latest bf756fb1ae65 14 months ago 13.3kB
[root@zhourui /]#

对容器进行修改后,想保存容器的状态,通过commit来提交,下次就可以使用自己提交的这个镜像了。就好比 vm 的快照功能。

容器数据卷

如果数据在容器中,那么将容器删除,数据就会丢失!需求,数据可持久化!!

MySQL容器删除,数据丢失,需求,MySQL数据可以存储在本地!!

容器之间可以有一个数据共享的技术。Docker容器中产生的数据,同步到本地。

这就是卷技术!将容器内的目录,挂载到主机上。

数据持久化和同步操作,容器间也是可以数据共享的。

使用数据卷

方式一:使用命令来挂载 -v

docker -it -v主机内的目录:容器内的目录
#测试
[root@zhourui home]# docker run -it -v /home/zrtest:/home centos /bin/bash #启动后使用 docker inspect 容器id 查看

使用 docker inspect 容器id 查看

测试文件的同步

1.停止容器

2.修改宿主机上的文件

3.启动容器,发现文件依旧是同步的

好处:以后修改只需要在本地修改即可,不需要进入容器!

部署MySQL

MySQL的数据持久化问题!

#获取镜像
docker pull mysql:5.7 #运行容器,数据挂载。安装mysql需要配置密码的,注意!
#官方测试连接方法
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag #启动MySQL
-d:后台运行
-p:端口映射
-v:数据卷挂载
-e:环境配置
--name:容器别名
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=123456 --name mysql01 mysql:5.7 #在本地连接上后创建一个test数据库,查看映射路径是否可以。

在本地使用Navicat测试连接

将容器删除后

[root@zhourui data]# ls
auto.cnf ca.pem client-key.pem ibdata1 ib_logfile1 mysql private_key.pem server-cert.pem sys
ca-key.pem client-cert.pem ib_buffer_pool ib_logfile0 ibtmp1 performance_schema public_key.pem server-key.pem test

可以看到test数据库还在,即挂载到本地的数据卷没有丢失,这就实现了容器数据的持久化。

具名挂载和匿名挂载

#匿名挂载
-P(大写P 随机映射端口)
-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx #查看所有的卷的情况
[root@zhourui home]# docker volume ls
DRIVER VOLUME NAME
local 42a60ffb1a9dfcefffdf269e3a08fcb9172a082babe6ea19b864d5f679eb4361
local 93e2f2060025965b83b0433b95e29ac325c25fa8684b79a12617438ffe898941
local 271ccfa1da7814fa8fceb5b482ce86009f97e29c09dca69bcc594a0d8fabb92a #匿名挂载:这里-v的时候只写了容器内的路径,没有写容器外的路径 #具名挂载
[root@zhourui home]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
3024685007a57eda45820c8c07920cea08b84b7847b86fd97f5f71f7100b8fbd
[root@zhourui home]# docker volume ls
DRIVER VOLUME NAME
local 42a60ffb1a9dfcefffdf269e3a08fcb9172a082babe6ea19b864d5f679eb4361
local 93e2f2060025965b83b0433b95e29ac325c25fa8684b79a12617438ffe898941
local 271ccfa1da7814fa8fceb5b482ce86009f97e29c09dca69bcc594a0d8fabb92a
local juming-nginx
[root@zhourui home]# #通过-v 卷名:容器内名字
#查看卷
[root@zhourui home]# docker volume inspect juming-nginx

所有docker容器内的卷,在没有指定目录的情况下都是在 /var/lib/docker/volumes/xxxx/_data。

通过具名挂载可以方便的找到我们的卷,大多数情况下都是使用具名挂载。

#如何确定是具名挂载还是匿名挂载,还是指定路径挂载
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载

拓展:

 #通过-v 卷名:容器内路径:ro或rw 改变读写权限
ro readonly #只读
rw readwrite #可读可写 #一旦设置了容器权限,容器对挂载出来的文件就有限定了
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx #只要看到ro,就说明这个文件只能通过宿主机来操作,容器内部是无法操作的!

初识Dockerfile

Dockerfile就是用来构建 docker 镜像的构建文件!命令脚本!

通过这个脚本可以生成镜像。镜像是一层一层的,脚本是一个个的命令,每个命令都是一层。

方式二:

[root@zhourui home]# pwd
/home
[root@zhourui home]# cd docker-test-volume/
[root@zhourui docker-test-volume]# pwd
/home/docker-test-volume
[root@zhourui docker-test-volume]# vim dockerfile #创建dockerfile
[root@zhourui docker-test-volume]# cat dockerfile #文件中添加以下内容后查看(文件中内容 指令(大写) 参数)
#每个命令就是镜像的一层
FROM centos VOLUME ["volume01","volume02"] #匿名挂载 CMD echo "....end...."
CMD /bin/bash [root@zhourui docker-test-volume]# docker build -f /home/docker-test-volume/dockerfile -t zhour/centos:1.0 .

#启动自己生成的容器
docker run -it 29e054de9dd4 /bin/bash
#在volume01中创建文件
[root@e224b7ebc0d7 volume01]# ls
[root@e224b7ebc0d7 volume01]# touch container.txt
[root@e224b7ebc0d7 volume01]# ls
container.txt
[root@e224b7ebc0d7 volume01]#

查看匿名卷挂载的路径:docker inspect 容器id

进入挂载的路径中查看

[root@zhourui /]# cd /var/lib/docker/volumes/f517ef934bb1d4376751cf0ec11608ed0fd287844436ba62cad973ce0f67dee8/_data
[root@zhourui _data]# ls
container.txt
[root@zhourui _data]#

可以看到文件已经同步!!

这种方式较常使用,通常用于构建自己的镜像。

假设构建镜像时没有挂载卷,需要手动挂载,-v 卷名:容器内路径。

数据卷容器

启动三个容器

#创建docker01
[root@zhourui /]# docker run -it --name docker01 29e054de9dd4
[root@255f9d13bea7 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var volume01 volume02 #创建docker02
[root@zhourui /]# docker run -it --name docker02 --volumes-from docker01 29e054de9dd4
[root@861b5d25a8ca /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var volume01 volume02 #在docker01的volume01中创建文件
[root@zhourui /]# docker attach 255f9d13bea7
[root@255f9d13bea7 /]# cd volume01
[root@255f9d13bea7 volume01]# ls
[root@255f9d13bea7 volume01]# touch docker01 #进入docker02的volume01中查看
[root@861b5d25a8ca /]# cd volume01
[root@861b5d25a8ca volume01]# ls
docker01 #创建docker03并在volume01中增加docker03文件
[root@zhourui /]# docker run -it --name docker03 --volumes-from docker01 29e054de9dd4
[root@7a405584084a /]# cd volume01
[root@7a405584084a volume01]# ls
docker01
[root@7a405584084a volume01]# touch docker03
[root@7a405584084a volume01]# ls
docker01 docker03 #在docker01中查看volume01
[root@255f9d13bea7 volume01]# ls
docker01 docker03
[root@255f9d13bea7 volume01]#

通过 --volumes-from 可以实现容器间的数据共享!!

可以测试删除掉 docker01 ,再去查看 docker02 和 docker03 ,数据仍然还在。

三个容器之间的文件是相互拷贝的,删掉一个不会丢失数据。

应用:多个 MySQL 或者 Redis 之间实现数据共享!!

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=123456 --name mysql01 mysql:5.7

docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
#可以实现两个MySQL之间的数据同步

结论:容器之间配置信息的传递,数据卷容器的生命周期是一直持续到没有容器使用为止。

通过 -v 将数据持久化到本地,本地的数据是不会删除的。

DockerFile

DockerFile介绍

dockerfile是用来构建 docker 镜像的文件。命令参数脚本。

构建步骤:

  1. 编写一个 dockerfile 文件
  2. docker build 构建成为一个镜像
  3. docker run 运行镜像
  4. docker push 发布镜像(dockerHub,阿里云镜像仓库)

查看官方 centos,点击版本会跳转至 GitHUb

很多的官方镜像都是基础包,一些功能没有,我们就需要自己搭建。

DockerFile构建过程

基础知识:

  1. 每个保留关键字(指令)必须是大写字母。
  2. 只需顺序从上到下。
  3. , 表示注释。

  4. 每个指令都会创建提交一个新的镜像层。

docker 是面向开发的,发布项目做镜像,就需要编写 dockerfile 文件。

Docker镜像逐渐成为企业交付的标准。

dockerfile :构建文件,定义了一切所需的环境和源代码。

dockerImage:通过 dockerfile 构建生成的镜像,最终发布和运行的产品。

docker 容器:容器是镜像运行起来后提供服务的。

DockerFile指令

FROM		#基础镜像,一切从这里开始构建
MAINTAINER #镜像是谁写的
RUN #docker 镜像构建的时候需要运行的命令
ADD #步骤:使用tomcat镜像,tomcat压缩包,就是添加的内容
WORKDIR #镜像的工作目录
VOLUME #挂载的目录位置
EXPOSE #暴漏端口配置
CMD #指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT #指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD #当构建一个被继承的 dockerfile 这个时候会运行 ONBUILD 的指令,触发指令
COPY #类似add命令,将文件拷贝拷贝到目录中
ENV #构建的时候设置环境变量

实战测试

Docker Hub 中99%的镜像都是由这个基础镜像 FROM scratch 来配置构建的

FROM scratch
ADD centos-8-x86_64.tar.xz /
LABEL \
org.label-schema.schema-version="1.0" \
org.label-schema.name="CentOS Base Image" \
org.label-schema.vendor="CentOS" \
org.label-schema.license="GPLv2" \
org.label-schema.build-date="20201204"
CMD ["/bin/bash"]

创建一个自己的 CentOS

#编写 dockerfile 的文件
[root@zhourui home]# cd dockerfile/
[root@zhourui dockerfile]# ls
[root@zhourui dockerfile]# vim mydockerfile-centos
[root@zhourui dockerfile]# cat mydockerfile-centos
FROM centos
MAINTAINER zhourr<813794474@qq.com> ENV MYPATH /usr/local
WORKDIR $MYPATH #进去后的工作目录,进去后 pwd 查看 RUN yum -y install vim #安装 vim
RUN yum -y install net-tools #安装后可以使用 ifconfig (不安装只能用 ip add) EXPOSE 80 CMD echo $MYPATH
CMD echo "...end..."
CMD /bin/bash #通过这个文件构建镜像
-f 构建文件路径
-t 镜像名:[tag]
最后有个 .
[root@zhourui dockerfile]# docker build -f mydockerfile-centos -t mycentos:0.1 .
...
Successfully built ddba7ccc7eee
Successfully tagged mycentos:0.1 #测试运行
docker run -it mycentos:0.1

默认的 centos 以下命令无法使用

[root@95c725dda358 /]# pwd
/
[root@95c725dda358 /]# vim
bash: vim: command not found
[root@95c725dda358 /]# ifconfig
bash: ifconfig: command not found
[root@95c725dda358 /]#

测试运行自己创建的镜像这些命令就可以使用了。

我们可以列出本地镜像的变更历史 docker history 镜像id

CMD和ENTRYPOINT的区别

CMD 		#指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT #指定这个容器启动的时候要运行的命令,可以追加命令

测试 CMD

[root@zhourui dockerfile]# vim dockerfile-cmd-test
FROM centos
CMD ["ls","-a"] #构建镜像
[root@zhourui dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .
....
Successfully built a44c7103184f
Successfully tagged cmdtest:latest
# run 运行,可以看到 ls-a 命令生效
[root@zhourui dockerfile]# docker run a44c7103184f
.
..
.dockerenv
bin
dev
etc
home
lib
... #追加一个 l ,希望返回 ls-al
[root@zhourui dockerfile]# docker run a44c7103184f -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:367: starting container process caused: exec: "-l": executable file not found in $PATH: unknown. #此时报错,因为使用CMD,-l替换了["ls","-a"],-l不是命令,所以报错
#需要使用以下完整命令
[root@zhourui dockerfile]# docker run a44c7103184f ls -al

测试 ENTRYPOINT

[root@zhourui dockerfile]# vim dockerfile-entrypoint
FROM centos
ENTRYPOINT ["ls","-a"] [root@zhourui dockerfile]# docker build -f dockerfile-entrypoint -t entrypointtest .
...
Successfully built 34773b8b0398
Successfully tagged entrypointtest:latest
[root@zhourui dockerfile]# docker run 34773b8b0398
.
..
.dockerenv
bin
dev
etc
home
lib
...
# 添加 -l,是可以直接追加到后面的,ls -a -l
[root@zhourui dockerfile]# docker run 34773b8b0398 -l
total 0
drwxr-xr-x 1 root root 6 Mar 27 14:51 .
drwxr-xr-x 1 root root 6 Mar 27 14:51 ..
-rwxr-xr-x 1 root root 0 Mar 27 14:51 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 15:22 bin -> usr/bin
drwxr-xr-x 5 root root 340 Mar 27 14:51 dev
drwxr-xr-x 1 root root 66 Mar 27 14:51 etc
drwxr-xr-x 2 root root 6 Nov 3 15:22 home
lrwxrwxrwx 1 root root 7 Nov 3 15:22 lib -> usr/lib

Docker中很多命令都十分相似,需要去对比测试一下,才能发现其中的区别。

实战 Tomcat镜像

  1. 准备镜像文件 tomcat 压缩包,jdk压缩包(放到home/zhour-tar目录下)

  2. 编写 Dockerfile 文件,官方命名:Dockerfile,build的时候会自动寻找这个文件,就不需要 -f 指定了。(在home/zhour-tar目录下,vim Dockerfile),压缩包会自动解压。

    FROM centos
    MAINTAINER zhourr<813794474@qq.com> COPY readme.txt /usr/local/read.txt ADD jdk-8u281-linux-x64.tar.gz /usr/local/
    ADD apache-tomcat-9.0.44.tar.gz /usr/local/ RUN yum -y install vim ENV MYPATH /usr/local
    WORKDIR $MYPATH ENV JAVA_HOME /usr/local/jdk1.8.0_281
    ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
    ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.44
    ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.44
    ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin EXPOSE 8080 CMD /usr/local/apache-tomcat-9.0.44/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.44/bin/logs/catalina.out
  3. 构建镜像

    [root@zhourui zhour-tar]# ls
    apache-tomcat-9.0.44.tar.gz Dockerfile jdk-8u281-linux-x64.tar.gz readme.txt
    #构建
    [root@zhourui zhour-tar]# docker build -t diytomcat .
  4. 启动镜像

    [root@zhourui zhour-tar]# docker run -d -p 3030:8080 --name zhoutomcat -v /home/zhour-tar/test:/usr/local/apache-tomcat-9.0.44/webapps/test -v /home/zhour-tar/tomcatlogs/:/usr/local/apache-tomcat-9.0.44/logs diytomcat
    
    
  5. 访问测试

  6. 发布项目(配置了数据卷挂载,直接在容器外编写项目就可以发布了)在test中新建

    web.xml

    <?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>

    index.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Hello zhourrr!!</title>
    </head>
    <body>
    Hello World!<br/>
    <%
    System.out.println("----my tomcat test----");
    %>
    </body>
    </html>
  7. 访问http://39.105.48.232:3030/test/

  8. 日志查看,cd /home/zhour-tar/tomcatlogs。cat catalina.out

需要掌握 Dockersfile 的编写!!

发布镜像

在 Docker Hub 上注册账号,在服务器登录后就可以提交自己的镜像了。

[root@zhourui tomcatlogs]# docker login --help

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

登录

[root@zhourui tomcatlogs]# docker login -u zhourui88
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded

提交

[root@zhourui tomcatlogs]# docker push diytomcat
Using default tag: latest
The push refers to repository [docker.io/library/diytomcat]
e21bfbb06ee5: Preparing
145f6d70801c: Preparing
f3ba2f2219d6: Preparing
f83a7c49f1e3: Preparing
2653d992f4ef: Preparing
denied: requested access to the resource is denied #拒绝
#需要增加一个tag
[root@zhourui tomcatlogs]# docker tag ea84d80641b1 zhourui88/tomcat:1.0
#查看
[root@zhourui tomcatlogs]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
diytomcat latest ea84d80641b1 About an hour ago 640MB
zhourui88/tomcat 1.0 ea84d80641b1 About an hour ago 640MB
#提交
[root@zhourui tomcatlogs]# docker push zhourui88/tomcat:1.0

提交的时候镜像也是按层级来提交的!

阿里云服务器

  1. 登录阿里云

  2. 找到容器镜像服务

  3. 创建命名空间

  4. 创建容器镜像

  5. 点击镜像仓库名 zhourui-test 浏览阿里云

#登录
[root@zhourui /]# sudo docker login --username=周锐822 registry.cn-beijing.aliyuncs.com
#提交到阿里云,这里没有更改tag,显示上传成功,但是我没有找到镜像
[root@zhourui /]# docker push zhourui88/tomcat:1.0
The push refers to repository [docker.io/zhourui88/tomcat]
e21bfbb06ee5: Layer already exists
145f6d70801c: Layer already exists
f3ba2f2219d6: Pushing [==========> ] 77.66MB/356.6MB
f83a7c49f1e3: Layer already exists #上传阿里云
[root@zhourui /]# sudo docker tag ea84d80641b1 registry.cn-beijing.aliyuncs.com/docker-zhourui/zhourui-test:1.0
[root@zhourui /]# docker images
REPOSITORY TAG IMAGE ID CREATED
diytomcat latest ea84d80641b1 3 hours ago
zhourui88/tomcat 1.0 ea84d80641b1 3 hours ago
registry.cn-beijing.aliyuncs.com/docker-zhourui/zhourui-test 1.0 ea84d80641b1 3 hours ago
[root@zhourui /]# docker push registry.cn-beijing.aliyuncs.com/docker-zhourui/zhourui-test:1.0

上传后查看

小结

Docker网络

理解 Dockers0

ip addr

#启动容器
[root@zhourui /]# docker run -d -P --name tomcat01 tomcat
72dee6c91e3f593c69858191014b9d228c6494b0aa049cd1f620350c1c46cd56
#查看容器内部网络地址 eth0@if123 ip地址 docker分配的
[root@zhourui /]# docker exec -it tomcat01 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
122: eth0@if123: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever #Linux去ping容器的内部
[root@zhourui /]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.062 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.045 ms

原理:我们每启动一个 docker 容器,docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0.

桥接模式,使用的技术是 evth-pair 技术

这时再输入 ip addr,发现多了一个网卡

再启动一个 tomcat02 发现又多了一个网卡 (docker run -d -P --name tomcat02 tomcat) ipaddr

查看tomcat02 ip addr

[root@zhourui /]# 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
124: eth0@if125: <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

可以发现容器的网卡都是一对一对的,【122: eth0@if123】【124: eth0@if125】。

evth-pair:就是一对虚拟设备接口,它们都是成对出现的,一段连着协议,一段彼此相连。

所以,evth-pair就充当一个桥梁,连接各种虚拟网络设备。

测试tomcat01和tomcat02之间能不能ping通:

[root@zhourui /]# docker exec -it tomcat02 ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.091 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.069 ms
#可以看到,容器之间是可以通信的

流程图理解

tomcat01 和 tomcat02 是公用一个路由器 docker0 。

所有容器不指定网络的情况下,都是 docker0 路由的,doker会给容器分配一个默认的可用 ip。

Docker使用的是 Linux 的桥接,宿主机中是 Docker 容器的网桥(Docker0)

Docker 中所有的网络接口都是虚拟的,虚拟的转发效率高。

只要删除容器,对应的网桥就没了。

docker network ls,docker network inspect (桥接network id)可以查看

--link

假设我们想通过容器的名字来ping,而不是通过ip,就需要使用 --link。

[root@zhourui /]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known #通过--link可以解决
[root@zhourui /]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
131bbb6e180687ff284ef2cabc78f4104dfc5d1018ee1e2f11a5b6e192bdc8bb
[root@zhourui /]# 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.101 ms #反向ping
[root@zhourui /]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known

docker network ls,docker network inspect (桥接network id)可以查看

--link 使用后,tomcat03在本地配置了tomcat02

[root@zhourui /]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 tomcat02 1fff64acaf04
172.17.0.4 131bbb6e1806

本质:在hosts的配置中增加了 tomcat02 的映射。

真实开发中,已经不建议使用 --link 了。

自定义网络,不使用 docker0。docker0不支持容器名连接访问。

自定义网络

查看所有的docker网络

[root@zhourui /]# docker network ls
NETWORK ID NAME DRIVER SCOPE
25000c3be4a4 bridge bridge local #桥接
b518cb3beba9 host host local
bcd06ce03d47 none null local

网络模式

bridge:桥接(docker默认)自己创建也使用 bridge 模式

none:不配置网络

host:和宿主机共享网络

container:容器内网络联通(局限性很大)

测试:

#直接启动,默认是 --net bridge 的,
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat #docker0特点,默认,域名不能访问,--link可以打通连接 #自定义网络
# --driver bridge
# --subnet 192.168.0.0/16
# --gateway 192.168.0.1
[root@zhourui /]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
6219f386e2bfc7f837554de2b011ec1d649d6eaafa617fcf4bdd2d8091cf82b2
[root@zhourui /]# docker network ls
NETWORK ID NAME DRIVER SCOPE
25000c3be4a4 bridge bridge local
b518cb3beba9 host host local
6219f386e2bf mynet bridge local
bcd06ce03d47 none null local

查看自己的网络:docker network inspect mynet

创建两个容器,连上自己的网络

[root@zhourui /]# docker run -d -P --name tomcat-net-01 --net mynet tomcat
c638c0cee8dff978e60532b9a1ddac74f10a45bfb6b542bf3fd3079f69ec5515
[root@zhourui /]# docker run -d -P --name tomcat-net-02 --net mynet tomcat
e9aee8d922b19af82f02e9e50b28a301ab10e7eb57828c454cb57b9ac5bdc0ae
[root@zhourui /]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "6219f386e2bfc7f837554de2b011ec1d649d6eaafa617fcf4bdd2d8091cf82b2",
"Created": "2021-03-28T17:29:39.571024726+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": {
"c638c0cee8dff978e60532b9a1ddac74f10a45bfb6b542bf3fd3079f69ec5515": {
"Name": "tomcat-net-01",
"EndpointID": "6d4ac08b616e2e33e8fb7a3e8659b5a6ff2e381083572dbe202f7b8598347177",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
},
"e9aee8d922b19af82f02e9e50b28a301ab10e7eb57828c454cb57b9ac5bdc0ae": {
"Name": "tomcat-net-02",
"EndpointID": "187733df51f17912e402211643ce7136cbb725d85a0c1045ef7e903471d9f878",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
] #再次测试 ping 连接
[root@zhourui /]# docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.115 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.067 ms
64 bytes from 192.168.0.3: icmp_seq=3 ttl=64 time=0.068 ms
^C
--- 192.168.0.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 67ms
rtt min/avg/max/mdev = 0.067/0.083/0.115/0.023 ms #不使用 --link。也可以ping名字了
[root@zhourui /]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.075 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.070 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.086 ms

自定义的网络donker帮我们维护好了关系,推荐使用自定义的网络。

应用:

redis:不同的集群使用不同的网络,保证集群是安全和健康的(192.168.xxx.xxx)

mysql:不同的集群使用不同的网络,保证集群是安全和健康的(192.182.xxx.xxx)

网络联通

创建两个容器在默认的docker0网络下

[root@zhourui /]# docker run -d -P --name tomcat01 tomcat
[root@zhourui /]# docker run -d -P --name tomcat02 tomcat

现在就有以下的四个容器在在 docker0 和 mynet 网络下。怎样去打通 tomcat01 连接到 mynet。

通过 --help 查看命令

测试打通 tomcat01 连接到 mynet

[root@zhourui /]# docker network connect mynet tomcat01
[root@zhourui /]# docker network inspect mynet #打通之后,tomcat01被放到了 mynet 网络下,
#一个容器两个 ip 地址

测试

[root@zhourui /]# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.092 ms
#反向也是可以ping通的
[root@zhourui /]# docker exec -it tomcat-net-01 ping tomcat01
PING tomcat01 (192.168.0.4) 56(84) bytes of data.
64 bytes from tomcat01.mynet (192.168.0.4): icmp_seq=1 ttl=64 time=0.118 ms
#tomcat02 是没有连接上 mynet 的
[root@zhourui /]# docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known

结论:如果需要跨网络操作,就需要使用 docker network connect 网络 容器名称 来联通!!

部署Redis集群

#创建redis的网络
docker network create redis --subnet 172.38.0.0/16 #通过脚本创建6个redis配置
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/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
cluster-announce-bus-port 16379
appendonly yes
EOF
done docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/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; \ #=====================================================================
#单个启动
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/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 /mydata/redis/node-2/data:/data \
-v /mydata/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 run -p 6373:6379 -p 16373:16379 --name redis-3 \
-v /mydata/redis/node-3/data:/data \
-v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf #创建集群
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 [root@zhourui /]# docker exec -it redis-1 /bin/sh
/data # 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
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: 1524f57c751c662847b24edb3cf4433e42e11dae 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
M: 3d0a68b584e5935b6174d8b8e0603a14eb246393 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
M: cce404917b84b790cf39ac1f6dff85c1c080c9a1 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
S: 2fb9e53fde60fb288e87a8bccf37f2d521c5f5be 172.38.0.14:6379
replicates cce404917b84b790cf39ac1f6dff85c1c080c9a1
S: d977bb4c2b2a45bbbeb74cc123bd87dba1acd257 172.38.0.15:6379
replicates 1524f57c751c662847b24edb3cf4433e42e11dae
S: 317ccf18aefe00a7a45820b6509bd8c9fc1f7097 172.38.0.16:6379
replicates 3d0a68b584e5935b6174d8b8e0603a14eb246393
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
..
>>> Performing Cluster Check (using node 172.38.0.11:6379)
M: 1524f57c751c662847b24edb3cf4433e42e11dae 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: cce404917b84b790cf39ac1f6dff85c1c080c9a1 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: 3d0a68b584e5935b6174d8b8e0603a14eb246393 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: 317ccf18aefe00a7a45820b6509bd8c9fc1f7097 172.38.0.16:6379
slots: (0 slots) slave
replicates 3d0a68b584e5935b6174d8b8e0603a14eb246393
S: d977bb4c2b2a45bbbeb74cc123bd87dba1acd257 172.38.0.15:6379
slots: (0 slots) slave
replicates 1524f57c751c662847b24edb3cf4433e42e11dae
S: 2fb9e53fde60fb288e87a8bccf37f2d521c5f5be 172.38.0.14:6379
slots: (0 slots) slave
replicates cce404917b84b790cf39ac1f6dff85c1c080c9a1
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered. /data # redis-cli -c
127.0.0.1:6379> cluster info
127.0.0.1:6379> cluster nodes
127.0.0.1:6379> set a b
-> Redirected to slot [15495] located at 172.38.0.13:6379
OK
172.38.0.13:6379> #新建窗口 docker stop redis-3
#获取 a 的值
127.0.0.1:6379> get a
-> Redirected to slot [15495] located at 172.38.0.14:6379
"b"

搭建redis集群完成!!

SpringBoot打包Dockers镜像

  1. 构建一个SpringBoot项目

    @RestController
    public class HelloController {
    @RequestMapping("/hello")
    public String hello(){ return "Hello zhour!";
    }
    }
  2. 打包应用,package

  3. 编写dockerfile

    FROM java:8
    
    COPY *.jar /app.jar
    
    CMD ["---server port 8080---"]
    
    EXPOSE 8080
    
    ENTRYPOINT ["java","-jar","app.jar"]
  4. 构建镜像(使用 ftp 将文件上传至服务器)

    [root@zhourui idea]# ls
    demo-docker-0.0.1-SNAPSHOT.jar Dockerfile
    [root@zhourui idea]# docker build -t boottestzr .
  5. 发布运行

    [root@zhourui idea]# docker run -d -P --name ideaboot-web boottestzr
  6. 访问

如需浏览器访问,阿里云开发端口,或者运行时 -p 暴漏已开放的端口即可!!

Docker学习笔记---通俗易懂的更多相关文章

  1. Docker学习笔记 — 配置国内免费registry mirror

    Docker学习笔记 — 配置国内免费registry mirror Docker学习笔记 — 配置国内免费registry mirror

  2. docker学习笔记1 -- 安装和配置

    技术资料 docker中文官网:http://www.docker.org.cn/ 中文入门课程:http://www.docker.org.cn/book/docker.html docker学习笔 ...

  3. Docker学习笔记之一,搭建一个JAVA Tomcat运行环境

    Docker学习笔记之一,搭建一个JAVA Tomcat运行环境 前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 Linux 系统上迅速创建一个容器(轻量级虚拟机)并部署和运行应用程序 ...

  4. docker~学习笔记索引

    回到占占推荐博客索引 使用docker也有段时间了,写了不少文章与总结,下面把它整理个目录出来,方便大家去学习与检索! docker~学习笔记索引 docker~linux下的部署和基本命令(2017 ...

  5. Docker学习笔记 - Docker容器内部署redis

    Docker学习笔记(2-4)Docker应用实验-redist server 和client的安装使用 一.获取redis容器(含客户端和服务端) 二.创建服务端容器 1.在终端A中运行redis- ...

  6. docker学习笔记(一)—— ubuntu16.04下安装docker

    docker学习笔记(一)—— ubuntu16.04下安装docker 原创 2018年03月01日 14:53:00 标签: docker / ubuntu 1682 本文开发环境为Ubuntu ...

  7. Docker学习笔记总结

    Docker学习笔记 https://yeasy.gitbooks.io/docker_practice/content/   一 环境搭建 Ubuntu安装 .添加软件源的GPG密钥 curl -f ...

  8. docker学习笔记二:常用命令

    docker学习笔记二:常用命令 查看docker常用命令 docker --help 返回结果如下: 其中常用的命令如下: 1.image相关操作 展示所有的image: 删除image: rmi ...

  9. docker学习笔记-1

    docker学习笔记一:安装 mac安装docker docker官方文档上有这么一段话: Because the Docker daemon uses Linux-specific kernel f ...

随机推荐

  1. sentry SSRF

    目录 Sentry介绍 exp测试步骤 自己构造blind发包 修复方式 参考 Sentry介绍 Sentry 是一个实时的事件日志和聚合平台,基于 Django 构建.一般在url上.或者logo上 ...

  2. mac 下如何轻松安装神器 Anaconda

    本文推荐使用homebrew 安装 1.打开终端执行 brew cask install anaconda3 然后就可以喝一杯咖啡了,终端会自动执行安装好 如果终端卡在update homebrew ...

  3. dubbo实战之一:准备和初体验

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  4. 绿色物流-智慧仓储监控管理 3D 可视化系统

    前言 随着电子商务产业的迅速发展,快递爆仓已成为了困扰仓储物流的一大难题.大量的碎片化订单,传统仓储管理和运作方式已无法满足,加速仓储物流管理的智能化.自动化升级创新,延伸而出的智慧物流概念成为物流行 ...

  5. 部署Angular应用到Github pages

    https://jeneser.github.io/blog/2017/08/08/angular-deploying-app-github-pages/ Published: August 08, ...

  6. python 常用库收集

    读者您好.今天我将介绍20个属于我常用工具的Python库,我相信你看完之后也会觉得离不开它们.他们是: Requests.Kenneth Reitz写的最富盛名的http库.每个Python程序员都 ...

  7. IntelliJ IDEA报错总结

    不能运行java程序 可能是没有选择运行环境点击 edit Configurations在Use classpath of module 中选择本项目的运行环境 Run报错: Error:java: ...

  8. mysql建表约束

    --mysql建表约束--主键约束它能够唯一确定一张表中的内容,也就是我们通过某个字段添加约束,就可以是的该字段唯一(不重复)且不为空.create table  user(    id int pr ...

  9. nodeJS详解2

    Nodejs应用场景 创建应用服务 web开发 接口开发 客户端应用工具  gulp webpack vue脚手架 react脚手架 小程序 NodeJs基于 Commonjs模块化开发的规范,它定义 ...

  10. SpringBoot-03 yaml+JSR303

    SpringBoot-03 yaml+JSR303 Yaml 1.配置文件 SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的 YAML是 "YAML Ain't a Ma ...