Docker基础教程

Posted IT飞牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker基础教程相关的知识,希望对你有一定的参考价值。

Docker基础教程

非常好的免费教程:狂神说视频教程地址

Docker是Go语言开发的;开源的;
Docker文档超级详细
文档地址:https://docs.docker.com/
仓库地址:https://hub.docker.com/
2016年发布第一版;

Docker能干嘛

比较DOcker和虚拟机技术的不同:

  • 传统虚拟机,虚拟出一条贱贱;运行一个完整的操作系统,然年后在这个系统上安装运行软件
  • 容器的应用直接运行在书主机的内容,容器是没有自己的内核的,也没有虚拟机虚拟我们的硬件,所以就请变了
  • 每个容器间是互相隔离,每个容器内都有一个属于自己的文件系统,互不影响;

DevOps

应用更快速的交付和部署

传统:已退帮助文档,安装程序

Docker:打报警想法不测试,一键运行

更便捷的升级和扩缩容

使用Docker之后,我们部署应用就和搭积木一样

项目打包为一个镜像,扩展 服务器A, 服务器B

更简单的系统运维

在容器化之后,我们的开发,测试环境都是高度一致的

更高效的计算资源利用

Docker是内核级别的虚拟化,可以在一个物理机上可以运行很多的容器实例!服务器的性能可以被压榨到极致;

只要学不死,就往死力学;

Docker安装

Docker的基本组成

镜像(image):docker静香就好比是一个模板,可以通过这个末班赖床吉安容器服务,tomcat镜像>run>tomcat01容器(提供服务器),通过这个奖项可以创建多个容器(最终服务器运行或者项目运行就是在容器中的)

容器(conrainer):Docker利用容器技术,独立运行一个或者一个组应用,ton故宫镜像赖床建的。

启动 停止 清除

仓库(respository):

安装Docker

参考官方文档:https://docs.docker.com/engine/install/ubuntu/

设置docker镜像仓地址的时候可以改用淘宝镜像

1. 安装/升级Docker客户端 镜像加速器

推荐安装1.10.0以上版本的Docker客户端,参考文档docker-ce

2. 配置镜像加速器

针对Docker客户端版本大于 1.10.0 的用户

您可以通过修改daemon配置文件 /etc/docker/daemon.json 来使用加速器

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'

  "registry-mirrors": ["https://j4z1a6if.mirror.aliyuncs.com"]

EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

Docker run运行原理图

底层原理

Docker是怎么工作的?

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

DockerServer接收到Docker-Client的指令,就会执行这个命令;

Docker为什么快

  • Docker有更少的抽象层

  • docker利用的是书主机的内核,vm需要是guest os

  • 所以说,新建一个容器的时候,docker不需要想虚拟机一样重新加载一个操作系统内核,避免引导,避免引导,虚拟机是加载guest os,分钟级别的,二docker是利用宿主机的操作系统吗,省略了这个复杂的过程,秒级!

之后学习完所有的命令,在回过头来看这段评论,就会很清晰!

Docker的常用命令

帮助命令

docker version
docker info     //镜像和容器的数量
docker --help

帮助文档的地址:https://docs.docker.com/engine/reference/run/

镜像命令

docker images:查看本地所有的镜像

  -a, --all             显示所有镜像
      --digests         
  -f, --filter filter   Filter output based on conditions provided
      --format string   Pretty-print images using a Go template
      --no-trunc        Don't truncate output
  -q, --quiet           Only show image IDs

docker search:搜索命令

 docker search mysql --filter=stars=3000

docker pull:下载镜像

docker pull 镜像名[:tag]

using default image latest 如果不写tag,默认是latest

指定版本下载:docker pull mysql:5.7

docker pull采用分层下载,好处是在下载同一个镜像的不同版本时,相同的层不用重复下载,极大的加速了下载的速度,减小下载镜像尺寸;

docker rmi 镜像名:删除时也只删除当前版本的文件

docker rmi -f 镜像id
docker rmi -f 镜像id1 镜像id2 镜像id3
docker rmi -f $(docker images -aq)    删除全部镜像

容器命令

有了镜像才可以创建容器,linux,下载一个centos镜像来测试学习

新建容器并启动

docker run [可选参数] image

--name  容器名字 comcat01 tomcat02,用来区分容器
-d 		后台运行
-it		使用交互方式运行,进入容器查看内容
-p		指定容器的端口 -p 8080:8080
	-p ip:主机端口:容器端口
	-p 主机端口:容器端口(常用)
	-p	容器端口
	容器端口
-P		随机指定端口

docker run -it centos /bin/bash 进入运行中的容器
exit		退出运行中的容器

查看运行中的容器

docker ps				查看运行中的容器
docker ps -a			查看所有容器
docker ps -n=2			查看最近创建的容器

删除容器

docker rm 容器id				删除指定容器
docker rm 容器id 容器id			删除指定多个容器
docker rm -f $(docker ps -aq)	删除全部容器
-f 		强制操作

启动和停止容器的操作

docker start 容器id
docker restart 容器id
docker stop 容器id
docker kill 容器id

常用其他命令

后台启动容器

docker run -d centos 		后台运行

查看日志

docker logs -f -t --tail 10 容器id			查看指定容器的10条日志

启动容器,并且自动打印日志

docker run -d centos /bin/bash -c "while true;do echo itren;sleep 1;done"
--tf		显示日志
--tail		显示条数

查看容器中进程信息

docker top 容器id

查看容器元信息

docker inspect 容器id

进入当前正在运行的容器

docker exec -it 容器it /bin/bash	//方式1:进入容器后,开启新的终端
docker attach 容器id					//方式2:进入容器正在执行的终端

作业

安装nginx

1、搜索镜像 docker search
2、拉取镜像	docker pull nginx
3、启动镜像 docker run -d --name ngixn01  -p 3344:80 nginx
4、查看启动的容器

端口暴露的概念


whereis nginx		查看nginx查看服务器目录

*/usr/share/nginx/html/index.html 路径是docker nginx虚拟主机中默认的代码路径;

思考问题:我们每次改nginx配置文件,都需要进入容器内部?我要是可以自容器外部提供一个映射路径,达到在容器修改文件名,容器内部就可以自动修改;

作业:docker来装一个tomcat

docker search tomcat --filter=stars=3000 搜索tomcat镜像
docker run -it --rm  tomcat:9.0		启动后,用完就删(测试时用)
docker run -d -p 3355:8080 --name tomcat01 tomcat	启动容器
docker exec -it 73be /bin/bash		进入容器

tomcat的默认代码目录是/usr/local/tomcat/webapps,

cp -r webapps.dist/* webapps   复制目录	
	-r	递归

思考问题,我们以后要部署项目,如果每次都要进入容器是不是十分麻烦?我要是可以在容器外部提供一个映射路径,webapps,我们在外部部署项目,就可以秀爱容器内部对应的文件;

作业:部署es+kibana

es 暴露的端口很多
es 十分的耗内存
es 的数据一般需要放置到安全目录!挂载

docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:8.3.2

下载并运行

启动之后,发现整个linux非常卡,1.xG  1核2G
停止整个docker
docker stats	查看状态

测试下es是否成功了;  curl localhost:9200


赶紧关闭,增加内存的限制
docker run -d --name elasticsearch03 --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xms512m" elasticsearch:8.3.2

可视化

portainer(先用这个)

Docker图形化界面管理工具!提供一个后端面板供我们操作!

docker search Portainer			搜索

docker run -d -p 8088:9000 \\
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

访问测试:

ip:8088

选择本地

登录后的界面

Rancher

commit镜像

docker commit 提交容器成为一个新的副本

docker commit -m ="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG]

实战测试

1、启动tomcat
	docker run -it -p 8080:8080 tomcat
2、进入容器
	docker exec -it 1892 /bin/bash
3、如果webapps目录文件为空,则拷贝webapps.dist内容到webapps中
	cp -r webapps.dist/* webapps
4、退出容器
	exit
5、提交镜像
	docker commit -a="it飞牛" -m="add webapps app" 1892 tomcat02:1.0 
6、再次查看生产的镜像
	docker images
	可以看到出现了tomcat02,以后我们就可以使用修改过后的镜像

运行成功后,页面如下:

如果想要保存当前同期的状态,我们可以使用commit,类似git commit

到了这里才算是入门的Docker!认真的吸收学习!

容器数据卷

docker的理念回顾

将应用和环境打包成一个镜像!

数据?如果输都在容器中,那么我们容器删除,数据就会丢失! **需求:数据可视持久化 **

MySql,容器删了,删库跑路!需求:MySql数据可以存储在本地!

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

这就是卷技术!目录的挂载,将我们容器内的目录,挂载到Linux上面!

总结一句话:容器的持久化合同步操作!容器间也可以数据共享的!

使用数据卷

方式一:直接食用命令来挂载 -v

1、创建容器,并映射挂载
	docker run -it -v /home/ceshi:/home centos /bin/bash
将容器中的home目录挂载到系统/home/ceshi目录上
2、查看容器信息
	docker inspect 0e71
3、在容器内/home中新建文件,会自动同步到容器外的/home/ceshi 目录
在容器外/home/ceshi 目录创建文件也会同步到容器内的/home目录中。实现容器内外挂载目录完全同步;

容器内

容器外

实战:安装MySql

推荐一个mysql可视化操作软件:SQLyog

1、获取镜像
	docker pull mysql:5.7
2、运行容器(配置musql密码:123123)
	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=123123 \\
        --name mysql01 \\
        mysql:5.7
        
-d 后台运行
-v 挂载
-e 环境配置
3、启动容器信息
	docker ps			看到mysql01已经启动
4、本地连接mysql是否启动成功(3310端口记得开放)
5、新建一个数据库first,外部/home/mysql/data中文件同步更新

mysql删除后,外部/home/mysql中的所有文件都会保留;这就实现了容器数据持久化功能;

具名和匿名挂载

上面还有一个指定路径挂载

匿名挂载
-v 容器内路径!
docker run -d -P --name nginx01 -v /etc/nginx nginx
不指定主机地址,-v后面直接写容器内路径
查看所有卷的情况
docker volume ls 
这里发现,这种就是匿名挂载,我们在-v只写了容器内的路径

具名挂载(-v后面不加/开头):
docker run -d -P --name nginx03 -v juming-nginx:/etc/nginx nginx
查看所有卷的情况
docker volume ls 

我们通过具名瓜子啊可以方便的找我们的一个卷,大多数情况在使用的具名挂载(推荐),尽量不要使用匿名挂载;

通过 -v 卷名:容器内路径

查看一下这个卷

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

查看卷信息

拓展:

通过 -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

DockerFile

Dockerfile介绍

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

构建步骤:

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

例如我们看下centos在docker仓库上的镜像包长什么样:

打开centos对应的源码地址,也就是一个基础的dockerfile配置文件,里面配置了一些基本的包,好多功能时没有的,需要启动完镜像后,自己进入容器中自行创建;

常见场景是:centos+jdk+mysql+tomcat+redis这样的容器能力,这个时候就需要手动去安装centos意外的能力;

dockerfile指定容器卷名称

dockerfile就是用来构建docker镜像的构建文件!命令脚本!先体验下

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

1、在/home/中新建 docker-test-volume 目录,这里统一存放挂载的具名卷
2、新建一个dockerfile文件,代码如下:
FROM centos
VOLUME ["volume01","volume02"]

CMD echo "----end----"
CMD /bin/bash
3、docker build -f dockerfile -t itfeiniu/centos:1.0 .
4、执行完成后,可以看到已经新建一个镜像

5、运行镜像 itfeiniu/centos
	docker run -it 镜像id /bin/bash

这个卷和外部一定是同步的,保存在默认的外部卷存储目录。

6、进入容器中volume01目录,新建一个container.txt文件
	cd volume01
	touch container.txt
7、退出容器,查看容器信息
	docker inspect 容器id
可以看到外部挂载目录的具体地址

8、打开目录可以看到在容器内部创建的container.txt文件

这种方式我们未来使用的十分多,因为我们通常会构建自己的镜像!

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

DockerFile构建过程

基础知识

  1. 每个保留关键字(指令)都是必须是大写字母

  2. 执行从上到下顺序执行

  3. #表示注释

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

    dockerfile是面向开发的,我们以后要发布项目,做镜像,就要编写dockerfile文件,这个文件十分简单!

    Docker镜像逐渐成为企业交付的标准,必须要掌握;

    Dockerfile:构建文件,定义了一切的步骤,源代码

    DockerImages:通过DockerFile构建生成的镜像,最终发布和运行的和产品!

    Docker容器:容器就是竞相运行起来提供服务器!

    DockerFile的指令

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

实战测试

Docker Hub中99%镜像都是从这个基础镜像过来的FROM scratch,然后配置需要的软件和配置来进行的构建

FROM scratch
ADD centos-7-x86_64-docker.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="20201113" \\
    org.opencontainers.image.title="CentOS Base Image" \\
    org.opencontainers.image.vendor="CentOS" \\
    org.opencontainers.image.licenses="GPL-2.0-only" \\
    org.opencontainers.image.created="2020-11-13 00:00:00+00:00"

CMD ["/bin/bash"]

创建一个自己的centos

#编写dockerfile的文件:dockerfile-centos
FROM centos
MAINTAINER itfeiniu<wjb2007_nice@126.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH			#指定进入容器后的工作目录
RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash
#打包
docker build -f dockerfile-centos -t mycentos:1.0 .

#运行
docker run -it mycentos:1.0
运行后进入容器,可以看到当前工作目录就是`/usr/local`

这里在 yum -y install vim 时,可能会下载不下来,需要切换国内yum源;

docker history 查看镜像构建过程

使用docker history [镜像名|镜像id]查看镜像构建过程。

我们平时看到一个镜像,可以通过history命令来学习下怎么做的。

CMD和ENTRYPOINT区别

CMD			#指定这个容器启动的时候需要运行的命令,只有最后一个会生效,可被替换;
ENTRYPOINT	#指定这个容器启动的时候需要运行的命令,可以追加命令	
创建一个dockerfile文件:dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]

1、构建
docker build -f dockerfile-cmd-test -t cmdtest:1.0 .
2、执行
docker run 镜像id
执行完后,控制台打印出根目录所有目录,如下:

3、如果在docker run 3306的时候加上-l,并不会把-l追加成 ls -a -l命令来执行,因为CMD不支持追加,而是会用命令行中参数替换CMD中参数。所以页面报错:

4、使用ENTRYPOINT命令参数,docker-cmd-test代码修改如下:
FROM centos
ENTRYPOINT ["ls","-a"]

docker build -f dockerfile-cmd-test -t cmdtest02 .
docker run 镜像id -l
这样会将-l追加都命令后面,打印如下:

实战:Tomcat镜像

  1. 准备镜像文件,tomcat压缩包,jdk的压缩包;

下载下面两个包:

apache-tomcat-9.0.22.tar.gz

jdk-8u333-linux-x64.tar.gz

  1. 编写dockerfile文件,官方命名:Dockerfile
touch readme.txt
vim 


#Dockerfile代码如下:
FROM centos

MAINTAINER itfeiniu<wjb2007_nice@126.com>

COPY readme.txt /usr/local/readme.txt

ADD jdk-8u333-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.22.tar.gz /usr/local/

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_333
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.22
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.22
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.22/bin/startup.sh && tail -F /url/local/apache-tomcat-9.0.22/bin/logs/catalina.out

  1. 构建镜像
   docker build -t diytomcat .
  1. 运行
docker run -d -p 9090:8080 --name itfeiniutomcat \\
   	-v /home/itfeiniu/build/tomcat/test:/usr/local/apache-tomcat-9.0.22/webapps/test \\
   	-v /home/itfeiniu/build/tomcat/tomcatlogs:/usr/local/apache-tomcat-9.0.22/logs \\
   	diytomcat

这里设置了两个数据卷挂载目录;

访问ip:9090路径,可以看到页面:

  1. 发布项目

    由于设置了目录挂载,我们不需要进入容器发布项目,只要到容器外部的挂载目录发布项目源码就行;

   #进入test目录
   cd test
   mkdir WEB.INF
   cd WEB.INF
   #创建web.xml,代码如下:
   <?xml version="1.0" encoding="UTF-8"?>
   <web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                               http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd"
       version="3.1">
   </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>itfeiniu</title>
   </head>
   <body>
   Hello World!<br/>
   <%
   System.out.println("--my test web logs--");
   %>
   </body>
   </html>

然后访问 ip:9090/test/,就能正常看到页面

发布自己的镜像

DockerHub

  1. 地址 https://hub.docker.com 注册自己的账号!
  2. 确定这个账号可以登录
  3. 在我们服务器上提交自己的镜像
root@iZuf6ecwnj4s314sstbr31Z:~# docker login -h
Flag shorthand -h has been deprecated, please use --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
  1. 登录完成完毕后,就可以提交镜像
docker login -u 用户名
  1. docker push推送镜像到在线仓库
docker images   #找到自己需要push的镜像包
docker push 镜像名:tag  #直接push可能会出现重名,导致push失败
#如果push失败,采用tag重命名后,再push,如下
docker tag  4f02 6feel/tomcat:1.0
docker push 6feel/tomcat:1.0

push后结果如下:

root@iZuf6ecwnj4s314sstbr31Z:~# docker push 6feel/tomcat:1.0
The push refers to repository [docker.io/6feel/tomcat]
d1fb32b900f6: Pushed 
576f6c7477f2: Pushed 
2fac4279b55f: Pushed 
74ddd0ec08fa: Mounted from library/centos 
1.0: digest: sha256:6fb9136b3dcae5fb009938196d3893919a96107e56d442228dab10e507665d24 size: 1161

#提交的时候也是按照镜像的层级来进行提交的!

推送成功后,进入hubDocker仓库能看到刚推送的镜像

阿里云镜像服务

  1. 进入阿里云,搜素容器镜像服务,进入个人版

  1. 创建命名空间

  2. 创建镜像仓库

    创建时选择本地仓库。

    创建成功后,自动跳转到仓库的新本信息页面,里面有详细镜像推送和拉取教程。

    基于前面我们已经打包6feel/tomcat镜像包,这里我们可以直接执行这

docker login --username=阿里云用户名 registry.cn-shanghai.aliyuncs.com
$ docker tag [ImageId] registry.cn-shanghai.aliyuncs.com/bilibili-feiniu/feiniu-test001:[镜像版本号]
$ docker push registry.cn-shanghai.aliyuncs.com/bilibili-feiniu/feiniu-test001:[镜像版本号]

推送成功后,控制台显示:

进入阿里云镜像版本,可以看到推送的镜像

以后,可以将自己的网站源码以及运行网站所需要的所有环境都push到远程。使用时只需要简单pull下来之后,就能把项目跑起来。

小结

数据卷容器

数据卷容器就是定义父容器,可以使用这个容器作为基础容器创建其他容器,其他容器挂载卷会指向父容器,一旦父容器有新增,子容器中的挂在卷也同步新增文件;

启动3个容器,通过--volumes-from创建数据卷容器;

docker run -it --name docker01 itfeiniu/centos    数据卷容器
docker run -it --name docker02 --volumes-from docker01 itfeiniu/centos
docker run -it --name docker03 --volumes-from docker01 itfeiniu/centos

可以看到在docker01容器volume01中创建的docker01文件,在docker02中的volume01目录中也同步出现了;如果docker01容器删除,不会删除docker02、docker03的数据;这里是一个拷贝的概念;

多个mysql同步数据!

docker run -d -p 3310:3306 \\
    -v /etc/mysql/conf.d \\
    -v /var/lib/mysql \\
    -e MYSQL_ROOT_PASSWORD=123123 \\
    --name mysql01 \\
    mysql:5.7

docker run -d -p 3311:3306 \\
    -e MYSQL_ROOT_PASSWORD=123123 \\
    --name mysql02 \\
    --volumes-from mysql01 \\
    mysql:5.7

结论:

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

但是一旦你挂载到了本地,这个时候,本地的数据是不会删除的!

Docker网络

需要彻底理解Docker网络,才能学习下面的企业实战、Docker Compose、Ci流水线等,否则很难看懂。

#在学习Docker网络之前首先清空镜像和容器。
docker rm -f $(docker ps -aq)
docker rmi -f $(docker images -aq)

理解Docker0

查看当前ip地址

ip addr

三个网络

问题,docker是如何处理容器网络访问的?

# 启动一个tomcat服务,创建容器1
docker run -d -P --name tomcat01 tomcat

#查看容器的内部网络地址 ip addr . 发现容器启动的时候会得到一个eth。查看容器ip也可使用docker inspect tomcat01。

可以看到容器的ip是127.17.0.2,尝试ping 127.17.0.2,也执行成功了!

所有linux和内部的容器之间的网络是相通的。

上传容器对应创建的网卡如下图:

如果我们再次创建一个容器

docker run -d -P --name tomcat02 tomcat
#系统会再次创建一组网卡,网卡成对出现:426+427,428+429,
426是linux中的网卡,427是容器中的网卡,两个网卡通过evth-pair技术做了绑定就能进行网络连接,实现通信。

新建的这个容器2ip是172.17.0.3,如果我们进入容器2内部,去ping 容器1的ip,也是可以ping通的。

docker exec -it tomcat02 /bin/bash     #进入容器2
apt-get update						#刷新源列表
apt-get install inetutils-ping		#安装ping命令
ping 172.17.0.2
#也可以这么执行
#返回到容器外部,执行下面代码:
docker exec -it tomcat ping 172.17.0.2

原理

  1. 我们每启动一个docker容器,docker就会给容器分配一个ip,并新建一组网卡,网卡成对出现。我们只要安装了docker,就会有一个网卡docker0桥接模式,使用的技术是evth-pair技术!
  2. 再启动一个容器测试,发现有多个了对网卡!

我们发现这个容器带拉网咖,都是一对对的

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

正因为有这个特性,evth-pair充当一个桥梁,连接各种虚拟网络设备的

OpenStac,Docker容器之间的链接,OVS的链接,都是使用evth-pair技术

容器和容器之间是可以ping通的!

小结:

Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥docker0。

Docker中的所有的网络接口都是虚拟的,虚拟的转发效率高!(内网传递文件)

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

思考一个场景,我们编写了一个微服务,database url=ip;项目不重启,数据库ip换掉了,我们希望可以处理这个问题,可以按照名字来进行访问容器?

容器互联–link

docker exec -it tomcat02 ping tomcat01   #这样是联不通的

#下面我们使用--link来创建tomcat03
docker run -d -P --name tomcat03 --link tomcat02 tomcat
#用tomcat02 ping tomcat03:失败

#用tomcat03 ping tomcat02:成功
#首先安装ping命令
docker exec -it tomcat03 apt-get update
docker exec -it tomcat03 apt-get install inetutils-ping
#ping成功
docker exec -it tomcat03 ping tomcat02

查看网络

docker network ls
docker network --help

docker network inspect bridge

# 之前我们是用的tomcat03连接的tomcat02,下面我们看下tomcat03的网络信息,是如何连接tomcat02的。
docker inspect tomcat03
# 可以看到在HostConfig配置中,存在Links配置项,我们知道Host是配置本地域名跳转用的,到这里大致可以猜测到可能是在tomcat03中配置了Host文件,类似 172.17.0.3  ->  tomcat02,这样的映射记录。

#为了验证,我们直接查看下tomcat03中的hosts文件
docker exec -it tomcat03 cat /etc/hosts
# 可以看到果然是有这样的配置

到这里我们知道ping tomcat03其实即使配置了tomcat03容器中的hosts文件,做了域名转发;那么刚刚在tomcat02中ping到tomcat03失败,也就可以解决。我们只要修改tomcat02中的host的文件,新增一条指向tomcat03的域名跳转。

#打开tomcat02中的hosts文件(vim如果没有安装的话,需要先安装)
docker exec -it tomcat02 vim /etc/hosts

#vim打开host之后,新增下面这条记录
172.17.0.4	tomcat03 f40398e290e3

#然后在执行ping命令,就通了
docker exec -it tomcat02 ping tomcat03

本质探究,–link其实就是在容器中新增一条hosts域名跳转

我们现在玩docker已经不建议使用–link

自定义网络,不适用docker0!

docker0问题:他不支持容器名连接访问!

进阶网络访问方式推荐是下面的自定义网络。

自定义网络

查看所有的docker网络

网络模式

bridge:桥接 docker(默认)

none:不配置网络

host:和宿主机共享网络

container:容器网络连通(用得好,局限很大)

测试

#开始前,清空所有容器。
docker  rm -f $(docker ps -aq)
#查看下网络
ip addr

可以看到,这时只剩下lo、eth0、docker0三个网卡,其他evth-pair网卡都已经被删除。

#我们直接启动的命令--net bridge,而这个就是docker0
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat

#docker0特点,默认,域名不能访问 ,--link可以打通阻塞

#我们可以自定义一个网络
#--driver bridge 
#--subnet 192.168.0.0/16 
#--gateway 192.168.0.1
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

#下面我们通过mynet来创建容器
docker run -d -P --name tomcat-net-01 --net mynet tomcat
docker run -d -P --name tomcat-net-02 --net mynet tomcat
#查看mynet关联信息,可以看到containers中已经新增了两个容器关联

#我们尝试在tomcat-net-01中ping向tomcat-net-02,是可以ping通的
docker exec -it tomcat-net-01 ping 192.168.0.3

直接ping 容器名也是通的
docker exec -it tomcat-net-01 ping tomcat-net-02

现在不适用--link也可以ping名字了!非常方便

我们自定义的网络docker都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络!

好处!

假如我们以后有很多集群,有redis集群和mysql集群,可以分配两个完全不同的网络集群,互不干扰。

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

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

网络连通

到这里,我们已经有两个网络,一个是默认的docker,和刚刚创建的mynet。

#在docker0下创建两个容器tomcat01、tomcat02。
docker run  -d -P --name tomcat01 tomcat
docker run  -d -P --name tomcat02 tomcat
#如果我们想要跨网络访问,是ping不通的,例如在tomcat01 ping
向 tomcat-net-01
docker exec -it tomcat01 ping tomcat-net-01
#这是可能连通的

需要使用network connect命令,实现网络和容器的连通

# 连通tomcat01  -》 mynet
# 连通之后就是将 tomcat01 放到了mynet 网络下
# 这个其实就是,一个容器两个ip地址!最典型的案例就是:阿里云服务,公网ip,私网ip
docker network connect mynet tomcat01	#连通mynet网络和tomcat01容器
docker network inspect mynet   	#查看mynet网络
# 连通之后,可以看到mynet网络中已经有tomcat01这个容器的配置

# 到这里,我们已经可以在tomcat01中ping通tomcat-net-01+tomcat-net-02
root@iZuf6ecwnj4s314sstbr31Z:~# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2): 56 data bytes
64 bytes from 192.168.0.2: icmp_seq=0 ttl=64 time=0.164 ms
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.094 ms
64 bytes from 192.168.0.2: icmp_seq=2 ttl=64 time=0.087 ms
^C--- tomcat-net-01 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.087/0.115/0.164/0.035 ms
root@iZuf6ecwnj4s314sstbr31Z:~# docker exec -it tomcat01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3): 56 data bytes
64 bytes from 192.168.0.3: icmp_seq=0 ttl=64 time=0.352 ms
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.111 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.079 ms
64 bytes from 192.168.0.3: icmp_seq=3 ttl=64 time=0.091 ms

结论:假设要瓜网络操作别人,就需要使用docker network connect连通!

实战:部署Redis集群

# 创建网卡
docker network create redis --subnet 172.38.0.0/16

创建完查看下网卡信息

root@iZuf6ecwnj4s314sstbr31Z:~# docker network ls
NETWORK ID     NAME                 DRIVER    SCOPE
5d83611f8b61   bridge               bridge    local
7f559704cf2a   redis                bridge    local

通过以下脚本创建六个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

执行完脚本,我看到6个节点已经创建

下面启动6个Redis容器,设置对应的容器数据卷挂载,

#第1个Redis容器
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
#第2个Redis容器
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
#第3个Redis容器
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
#第4个Redis容器
docker run -p 6374:6379 -p 16374:16379 --name redis-4 \\
    -v /mydata/redis/node-4/data:/data \\
    -v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \\
    -d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
#第5个Redis容器
docker run -p 6375:6379 -p 16375:16379 --name redis-5 \\
    -v /mydata/redis/node-5/data:/data \\
    -v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \\
    -d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
#第6个Redis容器
docker run -p 6376:6379 -p 16376:16379 --name redis-6 \\
    -v /mydata/redis/node-6/data:/data \\
    -v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \\
    -d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

或者通过脚本一次性启动6个Redis容器:

for port in $(seq 1 6); \\
do
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; \\
done

启动完成后,进入redis-1

docker exec -it redis-1 /bin/sh

进入redis-1容器后,创建集群,将1/2/3/4/5/6个redis容器都串联起来,高可用,负载均衡

redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6
379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1

连接成功,下面就可以操作集群了

#进入集群命令行模式
redis-cli -c

#查看集群信息
cluster info

#查看集群节点
cluster nodes


这里我们看出主从关系:

  • 主:redis-2 -> 从:redis-6

  • 主:redis-3 -> 从:redis-4

  • 主:redis-1 -> 从:redis-5

设置一个值

set a b
#redis-3设置了a,那么redis-4中也会有a的备份

然后退出集群,去停止redis-3容器

# ctrl+p+q
docker stop redis-3
停止了redis-3之后,再次进入集群取值a,正常从机redis-4会返回b值;linux上Docker安装gogs私服亲测(详解)

Docker Compose 入门(V3)

Docker镜像相关

Docker最全教程——从理论到实战

Docker基础教程

Docker基础教程