Docker

Docker学习路线

  • Docker概述
  • Docker安装
  • Docker命令
  • 镜像命令
  • 容器命令
  • 操作命令
  • ···
  • Docker镜像
  • 容器数据卷
  • DockerFile
  • Docker网络原理
  • IDEA整合Docker
  • Docker Compose
  • Docker Swarm

Docker概述

Docker能干嘛

虚拟机技术缺点:

  • 资源占用非常多
  • 冗余步骤多
  • 启动慢

容器化技术:

  • 不是模拟的一个完整的操作系统
  • 传统虚拟机,虚拟出一条硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件,而容器技术,是把应用直接运行在宿主机上,容器是没有自己的内核的,也没有虚拟硬件
  • 每个容器之间相互隔离,每个容器之间都有属于自己的文件系统,互不影响。

Docker安装

Docker的基本组成

客户端-服务器-仓库

镜像(image)

Docker镜像好比一个模板,可以通过这个模板来创建容器服务,比如Tomcat镜像=》run=》Tomcat容器。通过一个镜像可以创建多个容器,而最终的服务项目是运行在容器中的。

容器(container)

Docker利用容器技术,独立运行一个或者一组应用,通过镜像来创建。容器可以启动,停止,删除等。目前可以把容器理解为一个简易的linux系统。

仓库(repository)

Docker仓库就是存放镜像的地方,仓库分为共有仓库和私有仓库。Docker hub,阿里云···都有容器服务器(配置镜像加速)。

Docker底层原理

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

DockerSever 接收到Docker–Client的指令,就会执行这个命令。

Docker的常用命令


帮助命令

1
2
3
docker version       #显示docker的版本信息
docker info #显示docker的系统信息,包括容器和镜像的数量
docker 命令 --help #帮助命令

帮助文档的地址: https://docs.docker.com/engine/reference/ 右侧的command-line

镜像命令

docker images 查看所有本地主机上的镜像

1
2
3
#可选项:
-a --all #列出所有的镜像
-q --quiet #只显示镜像的id

docker search 搜索镜像

1
2
#可选项,通过隐藏来过滤
--filter=STARS=3000 #搜索出来的镜像就是STARS大于3000的,也就是下载量比较高的镜像了

docker pull 下载镜像

1
2
3
4
5
docker pull 镜像名[:tag]
如果不加tag就是,默认下载最新版本,latest
#指定版本下载: docker pull mysql:5.7 ---注意这个版本一定是docker hub里面写支持了,不是自己想写什么什么

#下载是分层下载,这是docker image的核心 联合文件系统

docker rmi 删除镜像 –这个i就是指的images,所以是删除镜像

1
2
#全部删除:
docker rmi -f $(docker images -aq) #后面返回所有的images的ID
容器命令

说明:有了镜像才会有容器,以centos为例

1
docker pull centos
新建容器并启动
1
2
3
4
5
6
7
8
9
10
11
12
docker run [可选参数] image
#参数说明
--name='NAME' 容器名字
-d 后台方式运行
-P 指定容器的端口
-P ip:主机端口:容器端口
-P 主机端口:容器端口
容器端口
-p 随机制定端口

#测试 启动并进入容器
>docker run -it centos /bin/bash
列出所有运行的容器
1
2
3
4
docker ps   
-a #列出当前正在运行的所有容器+带出历史运行过的容器
-n=numbers #显示最近创建的几个容器
-q #只显示容器编号
退出容器
1
2
exit          #容器停止并退出
Ctrl +P+Q #容器不停止退出
删除容器
1
2
3
4
docker rm    #没有加i说明不是image,就是容器了
#只rm不能删除正在运行的容器,如果要删除正在运行的,需要:
docker rm -f
docker rm -f $(docker ps -aq)
启动/停止容器
1
2
3
4
docker start 容器ID       #启动容器
docker stop 容器ID #停止当前正在运行的容器
docker restart 容器ID #重启容器
docker kill 容器ID #强制停止当前容器
常用其他命令

后台启动容器
1
2
3
4
5
#命令 docker run -d 镜像名
> docker run -d cnetos
#问题 > docker ps的时候发现centos停止了
#常见的坑,docker容器使用后台运行的,需要有一个前台进程,而docker发现没有应用,就会自动停止
#比如启动nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有进程了
查看日志
1
2
3
4
docker logs -f -t --tail n 容器ID
#显示日志
-tf #显示日志
--tail number #要显示的日志条数
查看容器中的进程信息
1
2
#命令
docker top 容器ID
查看进程的元数据
1
docker inspact 容器ID
进入当前正在进行的容器
1
2
3
4
5
6
7
8
#通常我们容器都是使用后台的方式运行的,有些时候我们需要进入容器,修改一些配置

#命令
docker exec -it 容器ID bashshell【例如/bin/bash】 #-it就是创建一个可交互的容器
docker attach 容器ID bashshell #进去之后就看到正在执行的命令
#二者的区别
docker exec #进入容器后,开启一个新的终端,可以在里面操作
docker attach #进入容器正在执行的终端,不会启动新的进程
从容器内拷贝文件到主机上
1
docker cp 容器ID:路径 目的的主机路径

Docker镜像详解


镜像是什么

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

所有的应用,直接打包docker镜像,就可以直接跑起来

如何得到镜像:

  • 远程仓库下载
  • 别人拷贝
  • Dockerfile自己制作一个镜像
Docker镜像加载原理

UnionFS(联合文件系统)

UnionFS(联合文件系统):Union文件系统是一种分层,轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同的目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union文件系统是Docker镜像的基础,镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像

特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会吧各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

镜像与容器

Docker镜像都是只读的,当容器启动之后,一个新的可写层被加载到镜像的顶部

这一层就是我们通常说的容器层,容器之下的都叫镜像层。我们创建一个镜像,然后run了之后在里面修改配置或者进行其他操作,这些操作都是基于容器层的,这个时候我们要把它发给其他人,需要把容器和镜像一起再重新打包。

commit镜像

1
2
docker commit 提交容器为一个新的副本
docker commit -m='提交的描述信息' -a='作者' 容器ID 目标镜像名:[TAG]
实战操作
1
2
3
4
5
6
7
#1.启动一个默认的Tomcat
#2.发现默认的Tomcat是没有webapps引用的,这是镜像的原因,官方默认的webapps下面是没有文件的
#3.于是我们进入容器,自己拷贝进去了基本的文件
#4.将我们操作过的容器通过commit提交为一个新的镜像
#以后就可以直接使用我们修改过的镜像

docker commit -m='add webapps app' -a='psych' 镜像ID Tomcat01:1.0

容器数据卷


什么是容器数据卷

docker理念回顾:将应用和环境打包成一个镜像

但是如果数据都在容器中,那么我们将容器删除的时候里面的数据也会跟着丢失,所以需求是如何使数据可持久化。所以我们急需一个容器之间可以数据共享的技术,也就是容器数据卷的技术

本质上就是目录的挂载技术,将容器内的目录挂载到Linux主机上

总结一句话:数据的持久化和同步操作


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

1
docker run -it -v 主机目录:容器内目录    #和端口映射很类似
实战操作:MySQL安装配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#获取镜像
> docker pull mysql:5.7
#运行容器,需要做数据挂载;安装启动mysql,需要配置密码,这是要注意的点
#官方命令:
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
#启动我们的:
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

#解释
-d #后台运行
-p #端口映射
-v #卷挂载
-e #环境配置,设置mysql登录密码
--name #设置容器名
具名和匿名挂载
1
2
3
4
5
6
7
8
9
10
11
12
13
#匿名挂载 
-v 容器路径
docker run -d -p --name nginx -v /etc/nginx nginx #不指定主机名
#现在我们来查看所有的volume[卷]的情况
docker volume ls
#就会显示很多匿名挂载,也就是我们在-v的时候只写了容器内的路径,没有写容器外的路径


#具名挂载
docker run -d -P --name nginx01 -v juming-nginx:/etc/nginx nginx
#然后我们再次查看volume的时候就会看到一个juming-nginx的卷,这个就是我们的具名挂载。
#然后我们要查看一个卷到底挂载到哪里了,就是用inspect查看详细数据就可以
> docker volume inspect juming-nginx

所有docker容器内的卷,没有指定容器外的路径的话,就会默认放在

/var/lib/docker/volumes/xxx/_data这个路径下面。

挂载分类
1
2
3
-v  容器内路径                     #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载

方式二:利用Dockerfile来构建docker镜像

Dockerfile其实就是一个命令脚本,然后通过一个脚本来生成一个镜像,镜像是一层一层的,脚本是一行一行的命令,对应一层一层的镜像。

1
2
3
4
5
6
7
8
#Dockerfile内容编写  ->  指令 参数    
#所有的指令都是大写
FROM centos

VOLUME["volume01","volume02"] # 挂载卷,匿名挂载,通过docker inspect来查看路径

CMD echo"__end__"
CMD /bin/bash
1
docker build -f Dockerfile -t psych-centos:1.0 .

Dockerfile


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

构建步骤:

  • 编写一个Dockerfile文件
  • docker build 构建成为一个镜像
  • docker run 运行镜像
  • docker push 发布镜像(DockerHub、阿里云镜像仓库)
DOckerfile构建过程

基础知识

  • 每个保留关键字(指令)必须都是大写字母
  • 执行从上到下顺序执行
  • #表示注释
  • 每一个指令都会去创建提交一个新的镜像层

Dockerfile是面向开发的,Docker镜像已经逐渐称为企业交付的标准

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

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

Docker容器:容器就是镜像运行起来提供服务的

Dockerfile指令

1
2
3
4
5
6
7
8
9
10
11
12
FROM             #基础镜像,一切从这里开始构建
MAINTAINER #镜像是谁写的,姓名+邮箱
RUN #镜像构建的时候需要运行的命令
ADD #步骤:比如:Tomcat镜像,就需要在centos的基础镜像中添加Tomcat压缩包
WORKDIR #镜像的工作目录
VOLUME #挂载的目录
EXPOST #暴露端口
CMD #指定这个容器启动的时候要运行的命令,之后最后一个会生效,可被替代
ENTRYPOINT #指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD #当构建一个被继承的Dockerfile,这个时候就会触发ONBUILD。
COPY #类似ADD,将文件拷贝到镜像中
ENV #构建的时候设置环境变量
实战测试1

Docker HUb中99%的镜像都是从一个基础镜像过来的。FROM scratch,然后设置需要的软件和其他的配置。

创建一个自己的centos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#Dockerfile
FROM cnetos
MAINTAINER psych<1836969156@qq.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD ehco $MYPATH
CMD echo '---end---'
CMD /bin/bash
1
2
docker build -f /path·· -t mycentos:0.1 .
#docker build -f dockerfile文件路径 -t 镜像名:[tag]

可以通过docker history 镜像ID 查看镜像构建过程(变更历史)

实战测试2

构建Tomcat镜像:

  • 准备镜像文件:Tomcat压缩包,jdk压缩包
  • 编写Dockerfile文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#Dockerfile
FROM centos
MAINTAINER psych<1836969156@qq.com>

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

ADD jdk-8ull-linux-x86.tar.gz /usr/local #ADD之后会自动解压
ADD apache-tomcat-9.0.22.tar.gz /usr/local

RUN uym -y install vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk.8.0_11
ENV CLASSPATH $JAVA_HOME/lib/dj.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINE_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 /usr/local/apache-tomcat-9.0.22/bin/logs/catalina.out
1
2
3
4
5
6
#构建镜像
docker build -t name .
#启动镜像
docker run -d -p 8888:8080 --name psychtomcat -v /home/psych/build/tomcat/test:/usr/local/apache-tomcat-9.0.22/webapps/test 容器name
#进入容器
docker exec -it 容器ID /bin/bash

Docker网络


Docker0

1
2
3
4
5
ip addr           #查看ip地址
出现三个地址
l0: 127.0.0.1 #本机回环地址
eth0: 172.17.90.138 #服务器公网地址
docker0: 172.18.0.1/16 #Docker帮我们生成的网卡地址
1
2
3
4
5
6
7
8
9
10
#问题:docker是如何处理网络访问的?

#我们随便启动一个容器,查看其ip地址,并尝试主机ping一下
docker run -d -P tomcat
docker exec -it tomcat ip addr #不进入容器,直接执行命令
#发现了两个网卡:
l0: 127.0.0.1/8
eth0@if162: 172.18.0.2/16 #docker分配的。
#主机尝试ping
ping 172.18.0.2 #发现主机可以ping通docker容器内部

原理

  • 我们每启动一个docker容器,docker就会给容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0,桥接模式,使用的技术是veth-pair技术
  • 启动一个容器,主机ip addr就会多一对网卡。veth-pair就是一对的虚拟设备接口,都是成对出现,一端连着协议,另一端彼此相连
  • 不同的容器和容器之间也是可以互相ping通的,因为docker0就想一个路由器一样,让各个容器之间能够ping
  • docker中所有的网络接口都是虚拟的,虚拟的转发效率高。