0%

Docker基础

Docker基础

基础知识

核心思想:打包装箱,每个箱子相互隔离

docker是基于Go语言开发的

虚拟机和容器的区别

  • 虚拟机的缺点

    image-20210922213015004

    • 资源占用多
    • 冗余步骤多
    • 启动很慢
  • 容器化技术

    image-20210922212953106

    docker特点:

    • 容器内应用直接运行在宿主机的内核,容器没有自己的内核,也没有虚拟硬件,较为轻便
    • 每个容器之间相互隔离,每个容器都有一个独立的文件系统,互不影响
    • 更简单的运维:
      • 打包镜像发布测试,一键运行
      • 更便捷的升级和扩容,测试环境高度一致
      • 更高效的计算资源利用:内核级的虚拟化

docker的组成

image-20210922214947781

安装docker

环境是阿里云ESC的CentOS7,操作系统不同可能指令略有差别

检测系统版本

1
cat /etc/redhat-release #检测CentOS系统版本

安装准备环境

1
2
3
# -y表示所有的询问都默认选yes
yum -y install gcc
yum -y install gcc-c++

安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#卸载之前环境(如果存在)
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

#安装依赖包
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
#配置阿里云镜像
sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#更新软件包索引
sudo yum makecache fast
#安装Docker CE(社区版)
sudo yum install -y docker-ce docker-ce-cli containerd.io

启动docker

1
2
3
4
5
6
7
8
9
10
#启动
systemctl start docker.service

#测试
docker version
docker run hello-world
docker images

#结束
systemctl stop docker.service

docker默认工作路径/var/lib/docker

阿里云镜像加速

1
2
3
4
5
6
7
8
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://lmdeal9c.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

Docker运行原理

docker run的运行流程

image-20210922221803263

Docker是一个CS结构的系统,docker的守护进程运行在主机上,通过socket从客户端访问

DockerServer接收Docker Client的命令并执行

image-20210922222202319

Docker为什么比虚拟机快?

image-20210922222402341

  • Docker比VM抽象层更少
  • 新建容器时,docker不需要像VM那样重新加载一个操作系统,避免引导,而docker是基于宿主机,资源占用更少

常用命令

系统命令

帮助文档地址Reference documentation | Docker Documentation

1
2
3
docker version #版本
docker info #系统信息,包括镜像和容器的数量
docker 命令 --help #获取帮助
  • 设置开机自启动

    1
    2
    3
    4
    5
    6
    #设置docker开机自启
    systemctl enable docker
    #运行容器时设置开机自启
    docker run --restart=always 容器名称或容器ID
    #未运行容器时设置开机自启
    docker update --restart=always 容器名称或容器ID

镜像命令

  • 查看镜像

    1
    2
    3
    docker images #查看所有镜像
    -a #显示所有镜像
    -q #只显示镜像id
  • 搜索镜像(也可以手动在dockerhub上搜索)

    1
    2
    docker search 镜像名 #在dockerhub上搜索镜像名
    --filter=STARS=3000 #搜索stars大于3k的镜像
  • 下载镜像

    1
    2
    3
    docker pull 镜像名 #下载镜像
    #例
    docker pull mysql:latest #可以通过[:tag]来指定版本
  • 删除镜像

    1
    2
    docker rmi 镜像id #删除指定id的镜像
    docker rmi -f ${docker images -aq} #删除所有镜像
  • 自定义新建镜像

    类似于VM的快照机制

    1
    2
    #原理与Git类似,注意只能提交有运行记录的容器
    dockerc commit -m="描述信息" -a="作者" 容器id 目标镜像名 :[TAG]

    我们commit过的容器将成为新的镜像保存在本地

容器命令

  • 运行容器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    docker run 镜像名或id #启动指定镜像

    #一些常用参数
    --name="" #指定容器名称,用于区分容器
    -d #后台方式运行
    -it #交互式运行,进入容器查看内容
    -p #指定端口
    -p ip:主机端口:容器端口 #绑定主机ip,端口与容器端口
    -p 主机端口:容器端口 #绑定主机端口与容器端口,如8080:8080
    -p 容器端口 #仅设定容器端口(外部无法连接)
    -P #随机指定端口
    --rm #测试运行,用完即删
    --net #指定运行网路(一般用于自定义网络)
    --restart=always #开机自启
    -e #一些额外参数
  • 查看容器

    1
    2
    3
    4
    docker ps #查看正在运行的容器
    -a #查看运行记录
    -n=num #显示num个最近创建的容器
    -q #仅显示容器编号
  • 进入容器

    1
    2
    3
    4
    5
    6
    7
    8
    #退出交互式容器
    exit #容器停止
    [ctrl] + [P] +[Q] #退出交互式,但容器不停止

    #进入交互式容器并开启新的终端
    docker exec -it 容器id /bin/bash
    #进入容器正在执行的终端,不会启动新的进程
    docker attach 容器id
  • 删除容器

    1
    2
    docker rm #删除容器
    docker rm -f ${docker ps -aq} #删除所有容器
  • 启动和重启

    1
    2
    3
    4
    docker start 容器id #启动容器(需要能在运行记录中找到id)
    docker restart 容器id #重启容器
    docker stop 容器id #停止
    docker kill 容器id #强制停止
  • 查看信息

    1
    2
    docker top 容器id #查看容器内部的进程信息
    docker inspect 容器id #查看容器的详细信息

    image-20210923134445856

    可以看到,docker容器id只是全部id前缀的部分截取

  • 文件拷贝

    1
    2
    3
    4
    5
    #将容器内的文件拷贝到容器外
    docker cp 容器id:/home/Test.java /home
    #将容器外的文件拷贝到容器内一般使用挂载盘符的方法实现
    #只是简单修改的话还是可以直接拷贝,或者直接
    docker cp /home/Test.java 容器id:/home

常用命令图解:

image

常见问题解决

  • 后台启动自动停止

    1
    2
    docker run -d centOS
    #后台运行后发现容器自动停止了

    原因:

    后台运行docker容器必须指定前台进程,否则docker发现自己没有提供服务就会自动停止

  • 查看日志

    1
    docker logs -f -t --tail 100 容器名或id

可视化

portainer

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

在开放对应的端口号之后就可以通过外部访问

自定义镜像

容器数据卷

1
docker volume ls #查看本地所有卷

如果数据保存在容器中,如果删除容器,数据也就会丢失,容器之间可以有一种数据共享的技术,Docker容器中产生的数据会同步到本地

卷技术:将容器内部的目录挂载到外部linux目录上,进行数据同步

目的:容器的持久化和同步操作,容器之间可以进行数据共享

直接使用命令挂载

1
docker run -it -v 主机目录:容器内目录 镜像名

示例

1
docker run -it -v ~/test:/home centos

使用inspect命令查看详细信息

image-20210923212031628

可以看到已经成功进行挂载,并且两边的文件夹已进行双向绑定,实际上是类似于硬链接的映射关系

具名和匿名挂载

其实就是挂载路径的体现方式

1
2
3
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /主机目录:容器内部目录 #指定路径挂载

使用docker volume ls查看所有卷

image-20210923215551997

  • 匿名挂载和指定路径挂在的卷名会自动生成
  • 匿名挂载和具名挂载的默认主机挂载点为/var/lib/docker/volumes/xxx/_data

读写权限

通过给-v属性最后添加:ro或:rw来限制容器内部的读写权限

1
2
docker run -it -v 主机目录:容器内目录:ro 镜像名 #容器内部目录只读权限
docker run -it -v 主机目录:容器内目录:rw 镜像名 #容器内部目录读写权限

通过DockerFile挂载

编写用来构建docker镜像的脚本文件

注意左侧的命令大写,右侧的属性可以大小写

dockerfile01

1
2
3
RROM centos
VOLUME ["volume01","volume02"]
CMD /bin/bash

利用Dockerfile构建容器并挂载

1
docker build -f ~dockerFile01 -t newVolumeCentos:1.0 . #注意最后有'.'

数据卷容器

多个容器同步数据

  • 先创建docker01容器,这里的newVolumeCentos:1.0是之前创建的自定义镜像

    1
    docker run -it --name docker02 newVolumeCentos:1.0
  • 使用--volumes-from属性指定挂载的容器

    1
    docker run -it --name docker02 --volume-from docker01 #之后docker01与docker02两个容器中的指定文件夹就进行了绑定

Dockerfile

构建自定义镜像的指令集合文件,默认名Dockerfile,如果在当前目录中编写了这个文件,构建镜像时就不需要-f指定Dockerfile文件

Dockerfile指令功能

指令必须大写,参数可以大小写

image-20210924105115681

我们还可以使用docker history 镜像名命令来查看镜像构建历史

CMD和ENTRYPOINT的区别

  • CMD:不能追加命令,如:

    DockFile中编写CMD ["ls","-a"]

    执行时docker run mycentos -l会报错

  • ENTRYPOINT:可以追加命令

    与CMD不同,上面例子中的docker run mycentos -l可以正确执行

Dockerfile示例

docker原生的centos镜像删减了许多功能,例如:

  • 没有设定工作目录,进入后默认在\路径
  • ifconfig不能使用
  • vim不能使用

我们可以对原生的centos镜像进行增强,使得上面这些功能可以使用

  • 先编写自己的Dockerfile

    myDockerfile

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    FROM centos
    MAINTAINER lan5th<lan5th@foxmail.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 "---finish build---"
    CMD "/bin/bash"
  • 构建镜像

    1
    docker build -f myDockerfile -t mycentos:0.1 .
  • 进入镜像

    1
    docker run -it mycentos:0.1

发布镜像

发布镜像到DockerHub

登录

1
docker login -u 用户名 #推荐执行之后再输入密码
1
docker push lan5th/mycentos:0.1 #发布镜像

注意:镜像名一般需要改为用户名/镜像名的格式

更改镜像名

1
docker tag mycentos:0.1 lan5th/mycentos:0.1

发布镜像到阿里云镜像仓库

  1. 进入阿里云容器镜像产品
  2. 创建个人实例并进入
  3. 创建命名空间
  4. 创建容器镜像
  5. 根据官方文档的操作进行镜像操作

Docker网络

veth-pair

成对的虚拟设备接口,充当着桥梁的身份,连接各种虚拟网络设备

当我们启动docker容器时,docker会为容器自动分配ip地址,并且每次启动分配到的ip地址可能不同

当我们启动两个centos容器时(使用ip addr查看网卡)

  • 主机所有网卡

    image-20210924143943084

    1:本机网卡

    2:阿里云网卡

    3:docker默认网卡

    41:centos-01网卡的主机接口

    43:centos-02网卡的主机接口

  • centos-01所有网卡

    image-20210924144251480

    1:主机网卡

    40:centos-01网卡的容器接口

  • centos-02所有网卡

    image-20210924144500082

    1:主机网卡

    42:centos-02网卡的容器接口

veth-pair桥接网卡图解:

image-20210924142936692

无需配置ip地址的网络交互

由于ip地址是docker自动分配的,当我们操作具体业务时不可能每次部署都要手动配置ip地址

解决方法:

  • 方式一:运行镜像时添加--link

    1
    docker run -d -P --name centos-02 --link centos-01 centos

    这种方式只能从centos-02连通centos-01,反之则不行

  • 方式二:自定义网络

    网络模式

    • bridge:桥接模式,一般自定义网络也使用桥接模式
    • none:不配置网络
    • host:和主机共享网络
    • container:容器网络连通(局限大,使用少)
    1
    docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

    使用docker network ls查看,发现我们的自定义网络已经创建成功

    image-20210924154021079

    以自定义网络创建新镜像

    1
    2
    docker run -it -P --name centos-01 --net mynet centos
    docker run -it -P --name centos-02 --net mynet centos

    从centos-01使用ping命令测试与centos-02的连接

    image-20210924154846899

    说明我们的自定义网络已经能够实现我们的目标

之前的配置能够实现同一网段中使用容器name互联,那么如何使网段之间也能实现相同的功能?

网络连通

网段之间直接连通是不现实的,但我们可以将容器与其他网段的网络进行连通

1
docker network connect 网络名 容器名 #连通指定网络和容器

相当于在指定网络和容器之间有新添加了一个网卡,之后就可以跨网段使用容器name进行互联

实战:部署SpringBoot项目

  1. maven package打包成jar包

  2. 编写Dockerfile文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    FROM java:8

    COPY *.jar /app.jar

    CMD ["--server.port=8080"]

    EXPOSE 8080

    ENTRYPOINT ["java","-jar","/app.jar"]
  3. 把这两个文件发送到服务器上

  4. 构建镜像

    1
    docker build -t myspringboot .
  5. 运行镜像

    1
    docker run -d -P --name lan5th-springboot-web myspringboot
  6. 查看容器运行端口docker ps

  7. 进行测试curl localhost:49155/hello