Docker

Docker简介

前言

问题

大型项目组件和运行环境相对复杂,部署时会碰到很多问题:

  • 依赖关系复杂,容易出现兼容性问题
  • 开发、测试、生产环境存在差异,不同部署的服务器存在差异

image-20220626105249118

Docker问题解决

Docker如何解决依赖兼容问题

  • 将应用的Libs(函数库),Deps(依赖)、配置与应用一起打包

  • 将某个应用放到一个隔离容器去运行,避免相互干扰

Docker如何解决不同环境的操作系统不同的问题:

要解决这个问题,先要了解一下操作系统结构

内核与硬件交互,提供操作硬件的指令

系统应用封装内核指令为函数,便于程序员调用,用户程序基于系统函数库实现功能

例如:Ubuntu和CentOS都是基于Linux内核,只是系统应用不同,提供的函数库存在差异,这就是用户程序不能跨系统运行的原因。

  • Docker将用户程序与所需要调用的系统函数库一起打包
  • 用户程序在运行到不同操作系统时,直接基于打包好的库函数,借助于操作系统的Linux内核来运行

image-20220626111505029

总结

Docker是一个开源的应用容器引擎

  • Docker允许将开发中将应用、依赖、函数库、配置打包形成可移植的镜像

  • Docker应用运行在容器中,使用沙箱机制,相互隔离

  • Docker镜像中包含完整运行环境,包括系统库函数,仅依赖系统的Linux内核,因此可以发布到任意Linux操作系统上运行,实现虚拟化

Docker和虚拟机的区别

image-20220630181037698

Docker是一个系统进程,而虚拟机是操作系统中的操作系统

虚拟机在操作系统中模拟硬件设备,然后运行另一个操作系统,例如在window系统中运行一个Ubuntu系统。

可以运行任意的Ubuntu应用。

image-20220626121645356

特性 Docker 虚拟机
性能 接近原生 性能较差
硬盘占用 一般为MB 一般为GB
启动 秒级 分钟级

Docker架构

image-20220630184857540

Docker包括三个基本概念

  • 镜像(Image):相当于一个root文件系统,Docker将应用程序及其依赖、函数库、环境、配置等文件打包在一起形成镜像文件。

  • 容器(Container):镜像中的应用程序运行后形成的进程就是容器,Docker对容器进行隔离,有独立的CPU、内存 等,对外不可见。

    镜像和容器的关系,类似于面向对象程序设计中的类和实例一样,Docker容器通过Docker镜像来创建。镜像是静态的定义,时用于创建Docker容器的模板,容器是镜像运行时的实体,是独立运行的一个或一组应用。容器可以被创建、启动、停止、删除、暂停等。

    image-20220626125142458

  • 仓库(Repository):一个代码控制中心,用来保存镜像。

image-20220626124824925

Docker使用客户端-服务端(C/S)架构模式

img

  • 服务端(server):Docker守护进程,负责处理Docker指令、管理镜像、容器等
  • 客户端(client):通过命令或RestAPI向Docker服务端发送指令,与Docker的守护进程通信。

image-20220626125845647

Docker的安装

CentOS Docker安装

安装

卸载

查看已经安装的docker
1
yum list installed |grep docker
下载已经安装的docker
1
yum -y remove xxx
删除旧版本即其相关依赖项
1
2
3
4
5
6
7
8
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

安装Docker Engine-Community

使用 Docker 仓库即Docker Engine-Community进行安装

在新主机安装Docker Engine-Community前,需要设置Docker仓库,之后可以从仓库安装和更新Docker

设置仓库
1
sudo yum install -y yum-utils device-mapper-persistent-data lvm2 --skip-broken

image-20220626210712373

设置稳定仓库
1
2
3
yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

image-20220626210628192

安装Docker Engine-Community
1
sudo yum install -y docker-ce docker-ce-cli containerd.io

image-20220626211100004

关闭防火墙

1
2
systemctl stop firewalld
systemctl disable firewalld

image-20220626132908943

启动Docker

1
2
3
systemctl start docker
systemctl status docker
systemctl enable docker

image-20220626133049860

查看docker版本

1
docker -v

image-20220626211521257

配置镜像加速

阿里容器镜像服务地址:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors

image-20220626211723068

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

Docker基本操作

镜像相关命令

镜像名称一般分两部分组成:[repository]:[tag]

没有指定tag时,默认是latest,代表最新版本的镜像

image-20220626212326961

镜像操作命令

通过Dockerfile构建本地构建镜像

1
docker build

从Docker Registry镜像服务器拉取镜像

1
docker pull

查看镜像

1
docker images

删除镜像

1
docker rmi

推送镜像

1
docker push

镜像压缩

1
docker save

加载压缩镜像

1
docker load

image-20220626212914211

查看docker命令

1
2
docker --help
docker xxx

image-20220626213134386

容器相关命令

image-20220709164840868

创建容器

1
docker run --name nginx -p 8080:80 -d nginx

参数说明:

  • docker run:创建并运行一个容器

  • -name:容器名称

  • -p 8080:80: 端口进行映射,将宿主机端口与容器端口映射,将本地 8080 端口映射到容器内部的 80 端口

  • -d nginx: 设置容器在后台运行

  • niginx:后台名称

查看日志

1
docker logs -f nginx

-f 持续更新日志信息

进入容器

1
docker exec -it nginx bash

参数说明:

  • docker exec:进入容器内部,执行命令
  • -it:给当前进入的容器构建一个标准输入输出终端,实现与容器的交互
  • bash:进入容器后执行的命令,bash是一个Linux终端交互命令

Docker安装MySQL

查看可用MySQL版本

访问 MySQL 镜像库地址:https://hub.docker.com/_/mysql

image-20220626213644151

拉取MySQL镜像

1
docker pull mysql

Dockerhub没有提供arm64架构的MySQL,但是MySQL官方提供了mysql/mysql-server

arm架构下拉取MySQL镜像

1
docker pull mysql/mysql-server

image-20220626224920659

1
docker pull --platform linux/x86_64 mysql

image-20220627091852496

查看本地镜像

1
docker images

image-20220627091949600

搜索可用镜像

1
docker search mysql

image-20220627101743575

运行MySQL

1
docker run --name mysql  -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d  mysql

参数说明:

  • -p 3306:3306 :映射容器服务的 3306 端口到宿主机的 3306 端口,外部主机可以直接通过 宿主机ip:3306 访问到 MySQL 的服务
  • MYSQL_ROOT_PASSWORD=123456:设置 MySQL 服务 root 用户的密码

image-20220709153240490

数据挂载

1
2
3
4
5
6
docker run -p 3306:3306 --name mysql \
-v /mydata/mysql/data:/var/lib/mysql \
-v /mydata/mysql/conf:/etc/mysql/conf.d \
-v /mydata/mysql/log:/logs \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql

arm架构下运行

1
docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql/mysql-server

–name:容器命名

-p:端口映射

image-20220627202412060

登录MySQL

1
2
docker exec -it mysql bash
mysql -uroot -p123456

连接MySQL

添加远程登录用户

1
2
3
4
5
6
7
#添加远程登录用户
CREATE USER 'root'@'%' IDENTIFIED BY 'root';
#
GRANT ALL ON *.* TO 'root'@'%';
flush privileges;
#修改密码
ALTER USER 'root'@'%' IDENTIFIED BY '13851176590++';

image-20220627210219722

查看用户数据库

1
2
3
show databases;
use mysql;
select host, user, plugin from user;

image-20220627210420003

远程连接测试

image-20220627211152025

image-20220627211216753

Docker安装Nginx

查看可用Nginx版本

访问Nginx镜像库版本地址:https://hub.docker.com/_/nginx

image-20220627212318153

拉取Nginx镜像

1
docker pull nginx:latest

image-20220627212905626

查看本地镜像

1
docker images

image-20220627213027744

运行Nginx

1
docker run --name nginx -p 8080:80 -d nginx

image-20220627213342836

参数说明:

  • –name nginx:容器名称
  • -p 8080:80: 端口进行映射,将本地 8080 端口映射到容器内部的 80 端口
    • -d nginx: 设置容器在在后台一直运行

镜像导出和加载

镜像导出

1
docker save -o nginx.tar nginx:latest

image-20220709155017994

镜像加载

删除镜像
1
docker rmi nginx:latest

image-20220709155218222

1
docker load -i nginx.tar

image-20220709155420618

运行容器

1
docker run --name nginx -p 8080:80 -d nginx

参数说明:

  • –name nginx-test:容器名称
  • -p 8080:80: 端口进行映射,将本地 8080 端口映射到容器内部的 80 端口
  • -d nginx: 设置容器在在后台一直运行

访问服务

image-20220709164017925

查看容器日志

1
docker logs -f nginx

image-20220709170822636

Docker安装Redis

查看Redis可用版本

image-20220709160742122

拉取Redis镜像

1
docker pull redis:latest

image-20220709160912161

运行Redis容器

1
docker run -itd --name redis -p 6379:6379 redis

image-20220709161215298

持久化运行Redis容器

1
docker run -itd --name redis -p 6379:6379 -d redis redis-server --appendonly yes

image-20220709184650774

使用Redis客户端

1
2
docker exec -it redis /bin/bash
redis-cli
1
docker exec -it redis redis-cli

image-20220709161905065

可视化工具连接Redis

image-20220709190614232

打包镜像

1
docker save -o redis.tar redis:latest

image-20220709162053955

删除容器和镜像

1
2
docker rm
docker rmi

1
docker load -i redis.tar

image-20220709162740876

数据卷

数据卷定义

数据卷主要用于解决容器与数据耦合的问题,即将容器与数据分离,解耦合,方便操作容器内数据,保证数据安全。

image-20220716114244206

数据卷(volume)是一个虚拟目录,指向宿主机文件系统中的一个目录。

image-20220716114631748

数据卷操作

1
docker volume [COMMAND]

docker volume命令是数据卷操作,根据命令后跟随command确定下一步操作

  • create-创建一个volume
  • inspect-显示一个或多个volume的信息
  • ls-列出所有的volume
  • prune-删除未使用的volume
  • rm-删除一个或多个指定的volume

image-20220716125125309

image-20220716125559541

image-20220716125638308

数据卷挂载

创建数据卷

1
2
3
docker volume create html
docker volume ls
docker volume inspect html

image-20220716135129339

运行容器并挂载数据卷

1
docker run --name nginx -p 8080:80 -v html:/usr/share/nginx/html -d nginx

数据卷挂载方式:-v nameName : /targetContainerPath

如果容器运行时Volume不存在,会被自动创建出来

image-20220716135701171

查看挂载目录

1
2
docker volume inspect html
cd /var/lib/docker/volumes/html/_data

image-20220716140349300

修改内容

1
vim index.html

image-20220716141200880

访问服务

image-20220719225705897

目录挂载

目录挂载和数据卷挂载的语法类似:

  • -v [宿主机目录]:[容器内目录]
  • -v [宿主机文件]:[宿主机文件]

创建目录

1
2
mkdir -p /tmp/mysql/data
mkdir -p /tmp/mysql/conf

挂载/tmp/mysql/data到mysql容器内数据存储目录

挂载/tmp/mysql/conf/hmy.cnf到mysql容器的配置文件

设置MySQL密码

运行容器

1
2
3
4
5
6
7
docker run \
--name mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-p 3306:3306 \
-v /tmp/mysql/conf/hmy.cnf:/etc/mysql/conf.d/hmy.cnf \
-v /tmp/mysql/data:/var/lib/mysql \
-d mysql

数据卷挂载方式对比

image-20220719232331514

  • 数据卷挂载耦合度低,由dokcer来管理目录
  • 目录挂载耦合高,需要我们自己来管理目录

Dockerfile自定义镜像

镜像结构

镜像时将应用程序及其需要的系统函数库、环境、配置、依赖打包而成

image-20220719233304550

镜像是分层结构,每一层称为一个Layer

  • BaseImage层:包含基本的系统函数库、环境变量、文件系统

  • Entrypoint层:入口,是镜像中应用启动的命令

  • 其他层:在BaseImage基础上添加依赖、安装程序、完成整个应用的安装和配置

Dockerfile

Dockerfile是一个文本文件,其中包含了一个个指令(Instruction),用指令来说明要执行什么操作来构建镜像。每一个指令都会形成一层Layer。

image-20220720120921273

基于java:8-alpine镜像构建Java项目为镜像

  • 新建一个空目录,在目录中新建一个文件

image-20220720141558745

  • 拷贝jar包到目录

image-20220720142621552

  • 编写Dockerfile文件
    • 基于java:8-alpine作为基础镜像
    • 将app.jar拷贝到镜像中
    • 暴露端口
    • 编写人口ENTRYPOINT
1
2
3
4
5
6
7
8
9
10
# 指定基础镜像
FROM java:8-alpine

# 拷贝java项目的包
COPY ./docker-demo.jar /tmp/app.jar

# 暴露端口
EXPOSE 8090
# 入口,java项目的启动命令
ENTRYPOINT java -jar /tmp/app.jar

image-20220720142611628

  • 使用docker build命令构建镜像
1
docker build -t javaweb:1.0 .

最后的.指从当前目录构建

image-20220720142801112

  • 使用docker run创建容器并运行
1
docker run --name javaweb -p 8090:8090 -d javaweb:1.0

image-20220720145638751

image-20220720145713672

DockerCompose

Docker Compose是一个用于定义和运行多个Docker容器应用的工具,

Docker Compose可以基于Compose文件帮助我们快速部署分布式应用,而无需手动一个个创建和运行容器。

Compose使用YAML文件配置应用服务,通过指令定义集群中的每一个容器如何运行。

image-20220721094915629

DockerCompose的安装

1
curl -L "https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

image-20220721110308195

image-20220721110437236

修改文件权限

修改文件权限为可执行

1
chmod +x /usr/local/bin/docker-compose

image-20220721110623950

测试是否安装成功

1
docker-compose --version

image-20220721132752027

Base自动补全命令

1
curl -L https://raw.githubusercontent.com/docker/compose/1.29.2/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose

image-20220721133210786

Docker Compose使用步骤

  • 使用DockerFile定义应用程序环境,一般需要修改初始镜像行为时才需要使用
  • 使用docker-compose.yml定义需要部署的应用程序服务
  • 使用docker-compose up命令将所有应用服务一次性部署

Docker-compose.yml常用配置

image

指定运行镜像的名称

1
image: <image_name>:<tags>

container_name

配置容器名称

1
container_name: <container_name>

ports

指定宿主机和容器的端口映射(HOST-宿主机端口:CONTAINER-容器端口)

1
2
3
# 将宿主机的3306端口映射到容器的3306端口
ports:
- <host_port>:<container_port>

volumes

将宿主机的文件或目录挂载到容器中(HOST:CONTAINER)

1
2
3
# 将宿主机文件挂载到容器内
volumes:
- <host_volumes>:<container_volumes>

environment

配置环境变量

1
2
environment:
- <env_param>=<env_value>

连接其他容器的服务(SERVICE:ALIAS)

1
2
3
# 可以以database为域名访问服务名称为db的容器
links:
- db:database

Docker Compose常用命令

构建、创建、启动相关容器

1
2
# -d表示后台运行
docker-compose up -d

指定文件启动

1
docker-compose -f docker-compose.yml up -d

停止所有相关容器

1
docker-compose stop

列出所有容器信息

1
docker-compose ps

容器网络管理

网络管理意义

容器的网络默认与宿主机、与其他容器相互隔离,且容器中可以运行一些网络应用,如nginx、web应用、数据库等,如果需要让外部可以访问这些容器中运行的网络应用,需要配置网络来实现。

不同的需求下,容器和宿主机的通信有不同的业务状态时,需要容器网络管理以达到管理不同业务下相关的网络配置。

Docker网络驱动模式的类型

  • bridge-桥接模式:默认的网络模式,类似虚拟机的nat模式
  • host-宿主模式:容器与宿主机之间的网络无隔离,即容器直接使用宿主机网路
  • none-禁用模式:容器禁用所有网络
  • overlay-覆盖模式:利用vxlan实现的bridge模式
  • macvlan-模式:容器具备MAC地址,使其在外部看来一台真实的网络设备

Docker在安装时,会自动创建bridge、host、none三个网络驱动

1
docker network ls

image-20220728101349811

Docker网络管理命令

查看帮助文档

1
docker network --help

image-20220728103531652

查看网络

1
docker network ls

image-20220728103852636

创建网络

1
docker network create

image-20220728104125387

-d 指定网络的驱动(不指定默认为bridge)

– subnet 指定子网网段(192.168.0.0/16)

– ip-range 指定容器的I范围

– gateway 子网的网关

网络删除

1
docker network rm

image-20220728105123725

查看网络详细信息

1
docker network inspect 

image-20220728105257769

使用网络

1
docker run/create --network 

默认情况下,docker创建或启动容器时,会默认使用名为bridge的网络

网络连接与断开

1
docker network connect/disconnect 

image-20220728105838471

单主机常见三种Docker网络类型

image-20220729231934850

Docker默认情况下有bridge、host、none三种网络类型

Centos容器镜像处理

Centos安装并启用ifconfig命令
1
yum provides ifconfig

image-20220729233311573

运行ipconfig命令

image-20220729235046317

拉取centos镜像
1
docker pull centos:centos7
运行centos容器并启用ifconfig命令
1
2
docker run -it centos:centos7
yum install net-tools

image-20220730003749530

从容器中创建镜像
1
docker commit adoring_noyce centos-net

image-20220730001949456

image-20220730002038580

bridge网络模式

容器默认使用的网络类型

  • 宿主机上需要单独的bridge网卡,docker默认创建的是docker0
  • 容器之间、容器与主机之间的网络通信是借助为每一个容器生成的一对veth pair虚拟网络设备进行通信的(一个在容器上,另一个在宿主机上)
  • 每创建一个基于bridge网络的容器,都会自动在宿主机上创建一个veth*虚拟网络设备。 外部无法直接访问容器。需要建立端口映射才能访问
  • 容器借由veth虚拟设备通过如docker0这种bridge网络设备进行通信
  • 每一容器具有单独的IP
  • bridge网络模式下宿主机与容器服务使用的端口可以重复

img

查看宿主机网络信息

image-20220730005753492

创建桥接模式容器
1
docker run -it centos-net   #由于容器创建默认使用桥接模式,所以这里不需要使用--network指定

image-20220730005943098

bridge网络模式下的端口映射:由于bridge网络模式的上述特点,访问bridge网络模式的设备时需要端口映射

端口映射格式
1
docker run -p

image-20220730010611166

host网络模式

容器完全共享宿主机的网络,网络没有隔离,可以说宿主机的网络就是容器的网络

  • 容器、宿主机上的应用所使用的端口不能重复
  • 外部能够直接访问容器,不需要端口映射
  • 容器ip就是宿主机的ip

img

1
docker run -it --network=host centos-net

image-20220730011055805

none网络模式

容器上没有网络,无需任何网络设备,外部无法访问

1
docker run -it --network=none centos-net

image-20220730004641932

只有一个本地回环lo网络设备

自定义网络

创建网络

1
docker network create --driver bridge test

image-20220730012139747

自定义网络创建容器

1
docker run -it --network=test centos-net

image-20220730012749262

成功分配网络内的ip地址(注意不同的网络之间是隔离的)

image-20220730014800371

不同的网络是相互隔离的,无法进行通信

image-20220730013923962

网络连接

1
docker network connect test 881852a511a6

image-20220730014615772

连接测试

1
docker attach 

image-20220730020059128

容器通信

同一网络容器通信

创建两个容器使用同一个网络,在同一个子网分配ip地址,可以相互访问

因此只要保证两个容器处于同一个网络中,就可以直接通过容器的ip地址在容器间进行通信

image-20220730115943556

Docker域名解析服务器

在大多数场景下,容器部署的ip地址是自动分配的,因此无法提前知道ip地址

我们可以借助Docker提供的DNS服务器,将域名解析成对应容器的ip地址,这样就直接访问域名来实现通信(注意:域名解析只能在用户自定义网络下生效,默认网络是不行的)

1
2
docker run -it --name=test01 --network=test centos-net 
docker run -it --name=test02 --network=test centos-net

image-20220730121326930

容器共享网络

创建并运行一个新的容器,将其网络指定一个容器的网络,使得两个容器使用同一个网络

1
docker run -it --name=test03 --network=container:test01 centos-net

image-20220730121726308

容器和外部通信

容器创建默认使用桥接模式,桥接模式创建一个虚拟网络,让容器在虚拟网络中,通过桥接器与外界相连。其中,数据包从容器内部的网络搭到达宿主主机再发送网络的过程最关键的是依靠NATj将地址进行转换,再利用宿主机的ip地址将数据包转发出去。

image-20220702232449520

通过NAT,容器可以实现访问外界,但是当外部主动连接容器时,我们可以直接创建容器时配置端口映射

1
docker run --name nginx -p 8080:80 -d nginx

-p:端口映射配置,将容器对外提供访问的端口映射搭到宿主机的端口上

-p 宿主端口:容器端口

当外部访问到宿主主机的对应端口时会直接转发给容器内