Docker基础详细讲解,看这一篇就够了!

Docker的详细讲解

一、Docker概述

1.Docker的作用

一款产品的开发往往需要多个开发环境,在以前,开发人员将项目打包好之后,经常会出现在我的电脑上能够正常运行,而在他的电脑上不能使用,原因就是产品开发所需要的环境不一样。

而现在,开发人员将产品以及它所对应的开发环境一起打包,这种就被称为镜像。这样就省去了开发环境的麻烦。

而docker的出现就是为了解决以上的问题,docker就相当于一个箱子(镜像),把每一个镜像隔离开来,互不干扰

2.Docker的好处

  1. 更能高效地利用资源,减去了硬件虚拟以及完整系统等额外的开销
  2. 更快的启动速度,Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间
  3. 运行环境的一致性,方便了应用的迁移,可以将在一个平台上的应用直接放在另一个平台上,不用担心开发环境的变化
  4. 同样也使得开发人员对于应用的维护和更新更加方便
Docker容器虚拟机(VM)
操作系统与宿主共享操作系统宿主机上运行宿主机的操作系统
存储大小镜像小,便于存储与传输镜像庞大(VMDK)
运行性能几乎无额外的性能损失操作系统额外CPU、内存消耗

为什么Docker会比虚拟机快的多?

  • Docker容器是直接使用的宿主的操作系统,这就意味着docker的硬件资源不用虚拟化,这就减低了操作系统的等内存额外的损耗
  • Docker不需要直接加载操作系统,不会浪费资源。

二、Docker的基本组成

1.镜像

镜像就相当于一个印刷机的模板,可以通过镜像来创建多个容器,也就是可以靠印刷机的模板印刷出很多相同的书籍,各个容器之间相互独立。

2.容器

  • 容器就是一个一个独立的应用,每个应用之间相互独立
  • 可以被启用、开始、停止、删除。足够安全
  • 可以把容器看作是一个简易版的Linux系统(包括root用户权限,进程空间,用户空间和网络空间等)和运行在其中的应用程序。

3.仓库

  • 仓库是集中存放镜像文件的地方。
  • 仓库和仓库注册服务器(Registry)是有区别的,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签
  • 仓库分为公开仓库(public)和私有仓库(private)两种形式
  • 最大的仓库是国外的Docker Hub,存放了大量的镜像文件。

三、Docker的工作原理

1.Docker的工作原理

Dokcer是一个Client-Server结构:Docker守护进程运行在主机上,通过Socket从客户端来访问这个守护进程,而守护进程接收到来自客户端的命令后,管理运行在主机上的容器以及进行资源的分配。

在这里插入图片描述

2.Docker镜像加载的原理

docker的镜像实际上是由一层一层的文件系统组成,这种层级的文件系统被称为UnionFS

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

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

在这里插入图片描述

但我们最终会看到

在这里插入图片描述

Docker镜像加载原理

典型的Linux文件系统由两部分组成,具体的原理就是:

  1. 首先启动bootfs(boot file system) :主要包含bootloader和Kernel,bootloader是引导加载内核Kernel到内存中,当加载镜像的时候,最底层就是bootfs。加载完毕后就被卸载了
  2. 再次启动rootfs(root file system) :在bootfs之上,包含Linux中典型的文件如/etc,/bin等标准目录和文件

启动完之后,所有的docker镜像都起源于一个基础镜像,当进行修改或增加内容时,就会在当前的镜像之上创建新的镜像层。

具体的来说就是:将挂载到统一虚拟文件系统下的多个目录分别设置成read-only,read-write等权限,而写操作实在read-only上的一种增量操作,不会影响到read-only目录。只会在此基础上进行操作。

img

总结:对于一个精简的OS来说,rootfs可以非常小,只需要包含基本的命令,工具和程序库就可以了,底层与宿主机共用一个内核,镜像本身只需要提供一个rootfs就可以了,这也就是为什么虚拟机往往几十G,而镜像容器只有几百M的原因。

四、Docker的命令使用

img

1.帮助命令

# 显示docker的版本信息
docker version

#显示docker的系统信息
docker info

#帮助命令
docker 命令 --help

在这里,如果你不是root用户,使用docker命令会频繁的需要sudo提权,所以为了解决这个问题,可以参考一下答案

#添加docker用户组,如果已经有了可以跳过
sudo groupadd docker 

#将user1用户加入到docker组中
sudo gpasswd -a user1 docker

#更新docker用户组
newgrp docker

如果你忘记了你的root的密码,并且你目前的用户可以提权,你可以做以下操作

sudo su root
passwd
# 然后重新设置密码

2.镜像命令

查看镜像

# 查看本机上所有的镜像
docker images
# 出现以下信息
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
hello-world   latest    bf756fb1ae65   12 months ago   13.3kB

# 解释
REPOSITORY	镜像仓库源
TAG			镜像的标签
IMAGE ID	镜像的ID
CREATED		镜像的创建时间
SIZE		镜像大小

#可以附带的参数
--all ,-a 列出所有的镜像
--quiet ,-q只显示镜像的ID

搜索镜像

docker search 镜像名

下载镜像

# 不指定版本默认是最新版的
docker pull 镜像名

# 指定版本下载,以mysql为例子
docker pull mysql:5.7

删除镜像

# 删除一个特定的镜像
docker rmi -f 镜像的ID

# 删除多个特定的镜像
docker rmi -f 镜像的ID 镜像的ID ...

# 删除所有镜像
docker rmi -f $(docker images -aq)

# 所有的镜像ID可以换成镜像名字

3.容器命令

创建容器

docker run [可选参数] image 标识
	--name 给容器命名
	-d 后台运行
	-it 交互式运行,进入容器内,开机并启动进入终端
		-i 交互式
		-t 终端
	-p端口转发,指定容器的端口
		-p 主机端口:容器端口
	-P 随机端口

# 进入容器的终端
docker run -it 容器 /bin/bash

查看容器状态

docker run -d --name ubuntu01 ubuntu

# 查看所有的容器的状态
docker ps -a 

# 判断当前正在进行的容器
docker ps

# 查看最近创建的1个容器
docker ps -n=1

启动和停止容器

# 启动容器
docker start ID

# 重启容器
docker restart ID 

容器的进入

# 开启容器
docker start ID

# 进入容器,exit退出后会关闭容器的运行,进入后不会开辟新的终端
docker attach ID

# 进入容器,exit退出后不会关闭容器,会开辟一个新的终端
docker exec -it ID /bin/bash

停止容器

# 暂停,内存不会释放相当于注销
docker stop

# 杀掉容器,内存释放,相当于关机
docker kill

删除容器

#查看容器内部的进程
docker top ID

#删除容器
docker rm 容器ID	

clear#删除所有容器
docker rm -f `docker ps -aq`

注意:后台启动的容器,如果没有前台的进程来提供服务,这个后台进程就会停止!

4.常用其他命令

查看日志

docker logs [可选参数] 容器ID
      --details        显示提供给日志的其他详细信息
  -f, --follow         跟踪日志输出
  -n, --tail string    指定要显示的日志条数 (默认为全部)
  -t, --timestamps     显示时间戳

查考镜像元数据

docker inspect 容器ID

主机与容器文件进行传输

#ubuntu01容器中test.py文件传输到本机bd文件夹下面。
docker cp ubuntu01:/root/test.py /home/bd	

#主机上的文件传到虚拟机上
docker cp /home/bd/PythonEnv/ ubuntu01:/root 

查看容器的资源消耗

docker stats 容器的ID

五、Docker实践

1.部署Nginx

docker search nginx

docker pull nginx

docker run -d --name nginx01 -p 3304:80 nginx

docker exec -it nginx01 /bin/bash

2.部署Tomcat

docker run -d --name tomcat01 -p 3355:8080 tomcat

3.部署elasticsearch和kibana

docker run -d --name elasticsearch01 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2#开启服务

服务器搭建ElasticSearch环境和kibana环境请看这里,注意这里不是利用docker搭建的

4. Commit镜像

一般的,我们通过镜像创建并启动容器,我们知道镜像是只读的,容器是可以写的,我们可以将这两者打包在一起组成一个新的镜像,这就叫做Commit镜像

docker commit -m="提交所描述的信息" -a=“作者” 容器的id 你要打包成的镜像名:[版本]

六、容器数据卷

doker是将应用和环境打包成一个镜像,通过容器来进行使用,容器可以随时删除和卸载,但是这就i出现了一个问题,当容器被删除之后,容器里面的数据也会被随之删除,这显然不是我们想要的结果,所以才有了容器数据卷的诞生。

数据卷技术的引入:我们希望Docker容器产生的数据可以自动同步到本地,这样容器删了数据并不会丢失;同时数据也可在容器之间共享。这就是卷技术,也就是目录的挂载。

1.挂载的命令

docker run -it --name ubuntu02 -v 主机目录:容器要同步的目录 Ubuntu /bin/bash 

如果你忘记了自己挂载的具体路径可以使用下面的方法

docker inspect 你想要查看的容器

# 找到下面的这一栏
"Mounts": [
            {
                "Type": "bind",
                "Source": "/home/docker/ubuntu02",#这就是那个资源目录
                "Destination": "/home",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }

2.具名挂载和匿名挂载

具名挂载

# 匿名挂载: -v:容器内路径(没有写容器外路径),自动生成同步路径
docker run -d -P --name nginx01 -v /etc/nginx nginx

# 查看所有volume的情况,默认在/var/lib/docker/volumes路径下创exit建容器卷,文件名是随机生成的
docker volume ls
  • 具名
    • -v 卷名:容器内路径
    • 文件名不是随机生成的
  • 指定路径挂载
    • -v 宿主机路径:容器内路径
  • 挂在后面加上:ro(只读),rw(只写)
# 具名挂载: -v 卷名:容器内路径
docker run -d -P --name nginx02 -v specific-nginx:/etc/nginx nginx

# 查看所有volume的情况
docker volume ls

# 查specific-nginx卷的具体信息
docker volume inspect specific-nginx

# 通过 容器内路径:ro/rw 限制读写权限
ro:read only 	#只读,该路径文件只能通过宿主机来操作,容器内无法操作
rw:read write	#可读可写

docker run -d -P --name nginx02 -v specific-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v specific-nginx:/etc/nginx:rw nginx

3.数据卷容器

docker run -it --name centos01 centos

docker run -it --name centos02 --volumes-from centos01 centos

docker run -it --name centos03 --volumes-from centos01 centos

image-20210129181811436

我们可以将docker01删除,但是docker01里面的数据就不会消失,而是保存在docker02和docker03之中。

七、DockerFile

1.Docker的简介

DockerFile是用来创建docker镜像的文件

image-20210129213822710

构建镜像的步骤就是:

  1. 编写一个dockerFile文件
  2. docker build构建一个镜像
  3. docker run运行镜像
  4. docker push发布镜像

2.DockerFile的构建

  1. 每个保留关键字(指令)都必须是大写
  2. 执行顺序是从上往下执行
  3. #代表注释
  4. 每条指令都会创建新的镜像层
FROM基础镜像,从此开始构建
MAINTAINER镜像作者,通常为姓名+邮箱
RUN镜像构建时需要执行的命令
ADD在镜像中需要添加的文件(比如基础镜像centos中要添加tomcat)
WORKDIR镜像的工作目录
VOLUME容器数据卷,挂载主机的目录
EXPOSE对外的暴露端口
CMD指定容器启动时要运行的命令(只有最后一个生效,可被替代)
ENTRYPOINT指定容器启动时要运行的命令(可以追加命令)
ONBUILD当构建一个被继承DockerFile时就会运行ONBUILD指令
COPY类似ADD,将文件拷贝到镜像中
ENV构建时的环境变量

3.编写自己的DcokerFile

3.1构建一个基础的Centos镜像

首先要编写DockerFile文件

FROM centos
MAINTAINER wy<123456789@qq.com>

ENV MYPATH /usr/local

WORKDIR $MYPATH

RUN yum -y install vim
Rum yum -y install net-tools

EXPOSE 8088

CMD echo $MYPATH
CMD echo "---end---"
CMD /bin/bash

命令: docker build -f dockerfile路径 -t 镜像名:[tag] .

# 编写dockerfile文件,官方命名为Dockerfile,这样就不需要通过-f指定,build时会自动寻找这个文件
docker build -f DockerFile的文件名字 -t mycentos:0.1 .

注意:1. 一定在最后面有一个点的

​ 2.可能会出现这样的问题:

Error: Failed to download metadata for repo 'appstream': Cannot prepare internal mirrorlist: No URLs in mirrorlist

​ 而上面的报错信息是因为CentOS Linux已经停止维护,官方推出了CentOS Stream项目,解决问题的原理请点击这里,更改之后的文件如下

FROM centos
MAINTAINER wy<123456789@qq.com>

ENV MYPATH /usr/local

WORKDIR $MYPATH

RUN cd /etc/yum.repos.d/
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
RUN yum makecache & update -y
RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 8088

CMD echo $MYPATH
CMD echo "---end---"
CMD /bin/bash
3.2构建Tomcat镜像

首先要准备Tomcat压缩包和JDK的压缩包,并将这两个压缩包放在服务器的同一个文件夹下

# DockerFile文件的编写
FROM centos
MAINTAINER zsr <2476785771@qq.com>

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

ADD jdk-8u341-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.65.tar.gz /usr/local/


ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk
ENV CALSSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.65
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.65
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

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

八、Docker网络

1.容器之间的网络互通

可以用ip addr来查看服务器内部网络的地址,可以发现三个地址。

  • 127.0.0.1 本机回环地址
  • 172.17.223.207 服务器内网IP地址
  • 172.18.0.1docker0的地址
docker是如何处理容器网络访问的?比如有一个tomcat容器,一个mysql容器;tomcat中运行着一个web项目,这个项目需要访问mysql。这是如何实现的呢?
  • 每启动一个容器,docker就会给容器分配一个ip地址,并且每次新增的网络地址都是一对一对的,这就是evth-pair技术。

  • 就是一对虚拟设备接口,成对出现,一段连着协议,一段彼此相连;容器内的88连接了主机的89,容器内的90连接了主机的91;

  • evth-pair充当了一个桥梁,实现了主机可以ping通容器内部ip地址,用于连接各种虚拟网络设备

那么 tomcar01和tomcat02 这两个容器能否ping通呢?

当然是可以的,因为两个容器内的ip地址都桥接了主机相应的ip地址,都与docker0地址处于同一网段,因此可以ping通,容器和容器之间是可以ping通的

image-20210216214529859

所有的容器在不指定网络的情况下,都是docker0路由分配的,容器被删除之后,与此相对的网络也会被删除

image-20210216221256027

2.自定义网络

# 查看所有的网络	
[root@zsr ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
81fa37acd3b5   bridge    bridge    local
d1c3276f2d1f   host      host      local
40b12350fa4a   none      null      local

当我们启动容器的时候会有默认的参数就是 --net bridge,也就是docker0

但是建议自定义网络

# 创建一个网络mynet,采用默认的桥接模式,子网地址192.168.0.0,网关192.168.0.1

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

docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
81fa37acd3b5   bridge    bridge    local
d1c3276f2d1f   host      host      local
2e6be259e1f4   mynet     bridge    local
40b12350fa4a   none      null      local

#查看自定义的网络的详细信息
docker network inspect mynet

优点:解决了docker0的弊端,可以直接通过容器名来访问,

应用:在不同的集群(redis,mysql)用不同的网络,使用自己的子网,保证集群的安全及健康

docker exec -it mynet-tomcat01 ping mynet-tomcat02

现在问题来了,tomcat01与mynet-tomcat01之间不互通,又该怎么办呢?

image-20210220234313302

解决办法

# 测试联通tomcat01到mynet-tomcat01
docker network connect mynet tomcat01
# 原理就是将tomcat01加入到了mynet的网络中

3.实现Redis集群部署

image-20210220235432787

3.1自定义一个网络
# 自定义一个网络
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
3.2创建六个容器
for ps in$(seq1 6);\
do \
docker run -d -p 637${ps}:6379 -p 1637${ps}:16379 --name redis-${ps} \
-v /mydata/redis/node-${i}/data:/data \
-v /mydata/redis/node-${i}/conf/redis.conf:/etc/redis/redis.conf \
--net redis --ip 172.38.0.1${ps} redis:6.0 redis-server /etc/redis/redis.conf
done
3.3查看集群信息
# 进入redis-1容器
docker exec -it redis-1 /bin/sh
# pwd
/data
# ls
appendonly.aof	nodes.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


# 连接集群查看信息
redis-cli -c

# 查看集群信息
cluster info   

# 查看集群节点信息,三主三从
cluster nodes    

实现了高可用,主机挂掉从机自动替代主机,效率极大的提高!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Indra_ran

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值