这是我参与「第三届青训营 -后端场」笔记创作活动的第1篇笔记。Docker

81 阅读10分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第1篇笔记。

虚拟机与docker

虚拟机技术缺点:

  1. 资源占用多
  2. 冗余步骤多
  3. 启动慢

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

  1. 传统虚拟机,虚拟出一套硬件,运行一个完整的操作系统,然后再这个系统上安装和运行软件。
  2. 容器内的应用直接运行再宿主机的内容,容器时没有自己的内核的,也没有虚拟硬件,所以就轻便了。
  3. 每个容器间是相互隔离的,每个容器内都有一个属于自己的文件系统,互不影响。

DevOps(开发、运维)

应用更快速的交付和部署

传统:一堆帮助文档,安装程序

docker:打包镜像发布测试,一键运行。

更便捷的升级和扩缩容

使用了docker后,部署应用就像搭积木

更简单的系统运维

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

更高效的计算资源利用

docker是内核级别的虚拟化,可以在一个物理机上运行很多的容器实例,充分发挥服务器的性能

Docker的基本组成

镜像(image) :docker镜像就好比是一个模板,可以通过这个模板来创建服务。如:tomcat-image 👉run👉tomcat01容器。可以通过这个镜像创建多个容器。

容器(container) :docker利用容器技术,独立运行一个或者一组应用,通过镜像来创建的。启动、停止、删除、基本命令。

目前可以把这个容器理解为一个建议的linux系统。

仓库(repository) :仓库就是存档镜像的地方。仓库分为共有仓库和私有仓库。

Docker原理

运行流程

底层原理

Docker是一个C/S结构的系统,docker的守护进程运行在主机上,通过socket访问。

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

Docker为什么比vm快

1.docker有着比虚拟机更少的抽象层

2.docker利用的是宿主机的内核,vm是用Guest OS

所以,新建一个容器的时候,docker不需要像虚拟机一样加载一个操作系统内核,避免引导。虚拟机是加载Guest OS,是分钟级别的,而docker是利用宿主机的操作系统,省略了这个复杂的过程,是秒级别的。

Docker的常用命令

帮助命令

docker version     # 显示docker的版本信息
docker info        # 显示docker的系统信息,包括镜像和容器的数量
docker 命令 --help  # 万能命令

帮助文档:docs.docker.com/reference/

镜像命令

docker images # 查看所有本地的镜像
\

可选项\

--all , -a Show all images (default hides intermediate images)
--digests Show digests
--filter , -f Filter output based on conditions provided
--format Pretty-print images using a Go template
--no-trunc Don’t truncate output
--quiet , -q Only show image IDs

docker search mysql # 搜索mysql镜像
\

可选项\

Name, shorthand Default Description
--filter , -f Filter output based on conditions provided
--format Pretty-print search using a Go template
--limit 25 Max number of search results
--no-trunc Don’t truncate output

docker pull mysql[:tag] # 下载mysql镜像,如果不写tag默认latest

docker rmi -f id  # 通过id删除指定容器
docker rmi -f id1 id2 id3  # 通过多个id删除多个容器
docker rmi $(docker images -aq) # 删除全部容器

容器命令

docker run [可选参数] image\

参数说明\

--name="name" 容器名字
-d   后台运行
-it   使用交互方式运行,进入容器查看内容
-p             指定容器的端口 -p 8080:8080
-p ip:主机端口:容器端口
-p 主机端口:容器端口
-p 容器端口
容器端口
-P   随机指定端口

docker ps  # 列出当前正在运行的容器

-a  # 列出当前正在运行的容器 + 历史运行过的容器
-n  # 显示最近创建的容器
-q  # 只显示容器的编号

exit  # 直接停止容器并退出
Ctrl + p + q  # 容器不停止退出

docker rm 容器id
docker rm -f $(docker ps -aq)
docker ps -a -q | xargs docker rm

docker start 容器id     # 开启容器
docker restart 容器id   # 重启容器
docker stop 容器id     # 停止正在运行容器
docker kill 容器id     # 杀死容器

常用命令

命令 docker run -d 镜像名\

docker run -d centos
\

问题docker ps,发现centos停止了\

\

常见的坑,docker容器使用后台运行,就必须要有一个前台进程,docker发现没有应用,就会自动停止。\

nginx容器启动后,发现自己没有提供服务,就会立即停止。

查看日志\

docker logs

-tf  # 显示日志
--tail 10  # 显示日志条数

查看容器中进程信息\

docker top 容器id

查看容器的元数据\

docker inspect 容器id

进入当前正在运行的容器\

\

方式一\

docker exec -it 容器id /bin/bash\

进入容器后开启一个新的终端,可以在里面操作\

\

方式二\

docker attach 容器id\

进入容器正在执行的终端,不会启动新的进程

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

docker cp 容器id:容器内路径 目的主机路径

阶段作业

部署Nginx

  1. docker search nginx
  2. docker pull nginx
  3. docker images
  4. docker run -d --name nginx3340 -p 3340:80 nginx(端口暴露)
  5. docker exec -it nginx3340 /bin/bash
  6. docker stop nginx3340
  7. docker rm nginx3340

Docker镜像

UnionFS(联合文件系统)

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

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

Dockers镜像加载原理

docker的镜像实际上时由一层一层的文件系统组成,这种层级的文件系统UnionFS。

分层原理

commit镜像

docker commit 提交容器成为一个新的副本
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[tag]

容器数据卷

docker的理念回顾

如果数据都在容器中,当容器被删除时,数据就会丢失。需求:数据可以持久化

mysql容器删除后,就可以准备跑路了。需求:mysql数据可以储存在本地

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

这就是卷技术。目录的挂载,将容器内的目录,挂载在宿主机上。(容器的持久化和同步操作!容器间也是可以数据共享的!)

使用数据卷

指定路径挂载\

docker run -it -v 主机目录:容器目录 centos /bin/bash
\

主机目录与容器目录双向绑定

实战:安装MySQL

下载\

docker pull mysql
\

启动\

-d 后台运行
-p 端口映射
-v 数据卷挂载
-e 环境配置
--name 容器命名
docker run -d -p 3306:3306 -v /usr/local/docker-volume/mysql/conf:/etc/mysql/conf.d -v /usr/local/docker-volume/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=Xu595082586 --name mysql3306 mysql

具名挂载与匿名挂载

匿名挂载\

-v 容器内路径
docker run -d -P --name nginx3340 -v /etc/nginx nginx\

-v 只写容器内的命令\


\

具名挂载\

-v 卷名:容器内路径
docker run -d -P --name nginx3340 -v juming-nginx:/etc/nginx nginx

上图说明:/etc/nginx nginx目录挂载在/var/lib/docker/volumes/juming-nginx/_data

-v 主机目录(绝对路径):容器目录  # 指定路径
-v 容器内路径        # 匿名挂载
-v 卷名:容器内路径    # 具名挂载
\

一下命令将报错\

docker run -d -P --name nginx03 -v nginxtest/in:/etc/nginx nginx

拓展:

:ro 只能通过宿主机操作,无法在容器内修改文件\

docker run -d -P --name nginx3340 -v juming-nginx:/etc/nginx:ro nginx
\

:rw\

docker run -d -P --name nginx3340 -v juming-nginx:/etc/nginx:rw nginx

初识DockersFile

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

通过脚本生成镜像\

\

第一步,写脚本文件\

FORM centos
VOLUME ["volume01", "volume02"]
CMD echo "-----end-----"
CMD /bin/bash

#第二步,build(命令结尾需要一个点)
docker build -f dockerfiletext -t single/nginx-single:1.0 .

数据卷容器

docker run -it --name docker01 single/centos

docker run -it --name docker02 --volumes-from docker01 single/centos
\

现象:docker容器运行后,宿主机与docker01存在数据卷\

docker02数据卷挂载在docker01上,docker02运行后,宿主机上不再生成新的数据卷。\

宿主机 <--> docker01 <--> docker02

DockersFile

dockerfile是用来构建docker镜像的文件

步骤:

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

DockerFile构建过程

  1. 每个保留关键字都必须是大写字母
  2. 执行从上至下
  3. #表示注释
  4. 每一个指令都会创建提交一个新的镜像层,并提交。

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

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

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

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

FROM # 基础镜像
MAINTAINER # 镜像作业,名字+邮箱
RUN # 镜像构建的时候需要执行的命令
ADD # 步骤,tomcat镜像,这个tomcat压缩包
WORKDIR # 镜像的工作目录
VOLUME # 挂载目录
EXPOSE # 暴露端口
RUN # 运行
CMD # 指定容器启动的时候的命令,只有最后一个会生效
ENTRYPOINT # 指定容器启动的时候的命令,可以追加命令
ONBUILD # 当构建一个被继承的DockerFile这个时候就会运行ONBUILD命令。
COPY # 类似ADD,将文件拷贝到镜像中
ENV # 构建的时候设置环境变量

实战:创建一个自己的centos

FROM centos

MAINTAINER 1999singlesingle_xu1999@163.com
ENV MYPATH /usr/local
WORKDIR MYPATH  RUNyumyinstallvim RUNyumyinstallnettools  EXPOSE80  CMDechoMYPATH\ \ 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 mydockerfile-centos -t mycentos:0.1 .

实战:Dockerfile制作tomcat镜像

FROM centos

MAINTAINER 1999singlesingle_xu1999@163.com
COPY readme.md /usr/local/readme.md
ADD jdk-8u151-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-10.0.0.tar.gz /usr/local/

RUN yum -y install vim

ENV MYPATH /usr/local
WORKDIR MYPATH  ENVJAVAHOME/usr/local/jdk1.8.0151 ENVCLASSPATHMYPATH\ \ ENV JAVA_HOME /usr/local/jdk1.8.0_151\ ENV CLASSPATH JAVA_HOME/lib/dt.jar:JAVAHOME/lib/tools.jar ENVCATALINAHOME/usr/local/apachetomcat10.0.0 ENVCATALINABASE/usr/local/apachetomcat10.0.0 ENVPATHJAVA_HOME/lib/tools.jar\ ENV CATALINA_HOME /usr/local/apache-tomcat-10.0.0\ ENV CATALINA_BASE /usr/local/apache-tomcat-10.0.0\ ENV PATH PATH:JAVAHOME/bin:JAVA_HOME/bin:CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080
CMD /usr/local/apache-tomcat-10.0.0/bin/startup.sh && tail -F /usr/local/apache-tomcat-10.0.0/bin/logs/catalina.out\

构建镜像(以dockerfile命名,就不需要用 -f mydockerfile)\

docker build -t diytomcat .

Docker网络

简介

  1. 本机回环地址
  2. 腾讯云内网地址
  3. docker0地址

docker是如果处理容器网络访问的?

启动tomcat容器\

docker run -d -P --name tomcat01 tomcat

查看容器内IP

90:eth0if91

再次查看主机IP

91:eth0if90

再启动一个tomcat02

启动tomcat容器\

docker run -d -P --name tomcat02 tomcat

发现,又多了一对网卡。veth-pair就是一对的虚拟设备接口,一段连着协议,一段彼此相连。正因为有这个特性,veth-pair充当一个桥梁,连接各种虚拟网络设备。

docker使用的是linux的桥接,宿主机中是一个docker容器的网桥docker0,docker中所有的网络接口都是虚拟的。只要容器删除,对应的网桥就会消失。

容器互联--link

tomcat02 直接ping tomcat01失败

--link\

docker run -d -P --name tomcat03 --link tomcat02 tomcat
\

成功\

docker exec -it tomcat03 ping tomcat02
\

失败\

docker exec -it tomcat02 ping tomcat03\

查看tomcat03容器的hosts

--link就是再hosts配置中增加了tomcat02的ip地址

(docker现在已经不建议使用--link)

自定义网络

查看所有网络\

docker network ls

网络模式

bridge:桥接(docker默认)

none:不配置网络

host:和宿主机共享网络

container:容器网络互连(用的少,局限性大)

测试

直接启动的命令 --net bridge,而这个就是我们的docker0\

docker run -d -P --name tomcat01 --net bridge tomcat\

docker0特点:默认;域名不能访问;可以使用--link打通连接\

\

可以自定义网络\

docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

将tomcat-net-01、tomcat-net-02放在mynet中\

docker run -d -P --name tomcat-net-01 --net mynet tomcat
docker run -d -P --name tomcat-net-02 --net mynet tomcat
\

查看mynet网络元数据\

docker network inspect mynet\

测试容器网络互联\

docker exec -it tomcat-net-01 ping tomcat-net-02
docker exec -it tomcat-net-02 ping tomcat-net-01\

都成功,自定义网络可以直接ping容器名

网络连通

再创建一个tomcat01\

。。。\

将tomcat01与mynet连通(一个容器两个ip)\

docker network connect mynet tomcat01