Docker学习笔记---通俗易懂
阅读原文时间:2021年05月07日阅读:1

目录

Docker

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

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

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

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

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

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

DevOps:开发 运维。

应用更快的交付和部署。

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

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

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

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

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

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 -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 <br /> --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镜像加载原理

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是用来构建 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

上传后查看

小结

理解 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)可以查看

假设我们想通过容器的名字来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集群完成!!

  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 暴漏已开放的端口即可!!

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章