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. Linux操作php.ini文件

    有时你使用的是别人搭建好的环境,不知道php.ini在哪里,或者好久没有修改配置了,已经忘记了路径在哪,所以在操作文件之前,得先要找到.ini路径. 找php.ini 方式一 $ php -i | g ...

  2. Elastic App Search 快速构建 ES 应用

    公号:码农充电站pro 主页:https://codeshellme.github.io App Search 是 Elastic 家族中的一个产品,它可以帮助我们(基于 ES)快速高效的构建搜索应用 ...

  3. 我给Apache顶级项目贡献了点源码。

    这是why技术的第 91 篇原创文章 这篇文章其实并没有什么技术性的分享,从我的角度而言,更多是记录和思考. 把我对于源码和之前写的部分文章反哺给我的一些东西,带来的一点点思考分享给大家. 一行源码 ...

  4. root 登录 lightdm freebsd下

    root 登录 lightdm freebsd下方法 pkg install lightdm-gtk-greeter lightdm 写入lightdm_enable="YES"到 ...

  5. 关于Java中Collections.sort和Arrays.sort的稳定性问题

    一 问题的提出   关于Java中Collections.sort和Arrays.sort的使用,需要注意的是,在本文中,比较的只有Collections.sort(List<T> ele ...

  6. rman全备脚本

    cat rman_back.sh #!/bin/bash source /home/oracle/.bash_profile   rman log=/u01/backup/backupall_rman ...

  7. 图解 | 原来这就是 class

    我是一个 .java 文件,名叫 FlashObject.java,叫我小渣就行. public class FlashObject {    private String name;    priv ...

  8. sqli-labs系列——第四关

    less4 第四关的sql语句是这样的: select * from user where id=("$id"); ?id=1")–+回显正常 order by 4报错, ...

  9. Kubernetes使用metric-server让HPA弹性伸缩运行

    监控架构概述 kubernetes监控指标大体可以分为两类:核心监控指标和自定义指标,核心监控指标是kubernetes内置稳定可靠监控指标,早期由heapster完成,现由metric-server ...

  10. 第27 章 : Kubernetes 安全之访问控制

    Kubernetes 安全之访问控制 本文将主要分享以下三方面的内容: Kubernetes API 请求访问控制 Kubernetes 认证 Kubernetes RBAC Security Con ...