Docker
Docker
Docker简介
前言
问题
大型项目组件和运行环境相对复杂,部署时会碰到很多问题:
- 依赖关系复杂,容易出现兼容性问题
- 开发、测试、生产环境存在差异,不同部署的服务器存在差异
Docker问题解决
Docker如何解决依赖兼容问题
将应用的Libs(函数库),Deps(依赖)、配置与应用一起打包
将某个应用放到一个隔离容器去运行,避免相互干扰
Docker如何解决不同环境的操作系统不同的问题:
要解决这个问题,先要了解一下操作系统结构
内核与硬件交互,提供操作硬件的指令
系统应用封装内核指令为函数,便于程序员调用,用户程序基于系统函数库实现功能
例如:Ubuntu和CentOS都是基于Linux内核,只是系统应用不同,提供的函数库存在差异,这就是用户程序不能跨系统运行的原因。
- Docker将用户程序与所需要调用的系统函数库一起打包
- 用户程序在运行到不同操作系统时,直接基于打包好的库函数,借助于操作系统的Linux内核来运行
总结
Docker是一个开源的应用容器引擎
Docker允许将开发中将应用、依赖、函数库、配置打包形成可移植的镜像
Docker应用运行在容器中,使用沙箱机制,相互隔离
Docker镜像中包含完整运行环境,包括系统库函数,仅依赖系统的Linux内核,因此可以发布到任意Linux操作系统上运行,实现虚拟化
Docker和虚拟机的区别
Docker是一个系统进程,而虚拟机是操作系统中的操作系统
虚拟机在操作系统中模拟硬件设备,然后运行另一个操作系统,例如在window系统中运行一个Ubuntu系统。
可以运行任意的Ubuntu应用。
特性 | Docker | 虚拟机 |
---|---|---|
性能 | 接近原生 | 性能较差 |
硬盘占用 | 一般为MB | 一般为GB |
启动 | 秒级 | 分钟级 |
Docker架构
Docker包括三个基本概念
镜像(Image):相当于一个root文件系统,Docker将应用程序及其依赖、函数库、环境、配置等文件打包在一起形成镜像文件。
容器(Container):镜像中的应用程序运行后形成的进程就是容器,Docker对容器进行隔离,有独立的CPU、内存 等,对外不可见。
镜像和容器的关系,类似于面向对象程序设计中的类和实例一样,Docker容器通过Docker镜像来创建。镜像是静态的定义,时用于创建Docker容器的模板,容器是镜像运行时的实体,是独立运行的一个或一组应用。容器可以被创建、启动、停止、删除、暂停等。
仓库(Repository):一个代码控制中心,用来保存镜像。
Docker使用客户端-服务端(C/S)架构模式
- 服务端(server):Docker守护进程,负责处理Docker指令、管理镜像、容器等
- 客户端(client):通过命令或RestAPI向Docker服务端发送指令,与Docker的守护进程通信。
Docker的安装
CentOS Docker安装
安装
卸载
查看已经安装的docker
1 | yum list installed |grep docker |
下载已经安装的docker
1 | yum -y remove xxx |
删除旧版本即其相关依赖项
1 | sudo yum remove docker \ |
安装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 |
设置稳定仓库
1 | yum-config-manager \ |
安装Docker Engine-Community
1 | sudo yum install -y docker-ce docker-ce-cli containerd.io |
关闭防火墙
1 | systemctl stop firewalld |
启动Docker
1 | systemctl start docker |
查看docker版本
1 | docker -v |
配置镜像加速
阿里容器镜像服务地址:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
1 | sudo mkdir -p /etc/docker |
Docker基本操作
镜像相关命令
镜像名称一般分两部分组成:[repository]:[tag]
没有指定tag时,默认是latest,代表最新版本的镜像
镜像操作命令
通过Dockerfile构建本地构建镜像
1 | docker build |
从Docker Registry镜像服务器拉取镜像
1 | docker pull |
查看镜像
1 | docker images |
删除镜像
1 | docker rmi |
推送镜像
1 | docker push |
镜像压缩
1 | docker save |
加载压缩镜像
1 | docker load |
查看docker命令
1 | docker --help |
容器相关命令
创建容器
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
拉取MySQL镜像
1 | docker pull mysql |
Dockerhub没有提供arm64架构的MySQL,但是MySQL官方提供了mysql/mysql-server
arm架构下拉取MySQL镜像
1 | docker pull mysql/mysql-server |
1 | docker pull --platform linux/x86_64 mysql |
查看本地镜像
1 | docker images |
搜索可用镜像
1 | docker search mysql |
运行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 用户的密码
数据挂载
1 | docker run -p 3306:3306 --name mysql \ |
arm架构下运行
1 | docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql/mysql-server |
–name:容器命名
-p:端口映射
登录MySQL
1 | docker exec -it mysql bash |
连接MySQL
添加远程登录用户
1 | #添加远程登录用户 |
查看用户数据库
1 | show databases; |
远程连接测试
Docker安装Nginx
查看可用Nginx版本
访问Nginx镜像库版本地址:https://hub.docker.com/_/nginx
拉取Nginx镜像
1 | docker pull nginx:latest |
查看本地镜像
1 | docker images |
运行Nginx
1 | docker run --name nginx -p 8080:80 -d nginx |
参数说明:
- –name nginx:容器名称
- -p 8080:80: 端口进行映射,将本地 8080 端口映射到容器内部的 80 端口
- -d nginx: 设置容器在在后台一直运行
镜像导出和加载
镜像导出
1 | docker save -o nginx.tar nginx:latest |
镜像加载
删除镜像
1 | docker rmi nginx:latest |
1 | docker load -i nginx.tar |
运行容器
1 | docker run --name nginx -p 8080:80 -d nginx |
参数说明:
- –name nginx-test:容器名称
- -p 8080:80: 端口进行映射,将本地 8080 端口映射到容器内部的 80 端口
- -d nginx: 设置容器在在后台一直运行
访问服务
查看容器日志
1 | docker logs -f nginx |
Docker安装Redis
查看Redis可用版本
拉取Redis镜像
1 | docker pull redis:latest |
运行Redis容器
1 | docker run -itd --name redis -p 6379:6379 redis |
持久化运行Redis容器
1 | docker run -itd --name redis -p 6379:6379 -d redis redis-server --appendonly yes |
使用Redis客户端
1 | docker exec -it redis /bin/bash |
1 | docker exec -it redis redis-cli |
可视化工具连接Redis
打包镜像
1 | docker save -o redis.tar redis:latest |
删除容器和镜像
1 | docker rm |
1 | docker load -i redis.tar |
数据卷
数据卷定义
数据卷主要用于解决容器与数据耦合的问题,即将容器与数据分离,解耦合,方便操作容器内数据,保证数据安全。
数据卷(volume)是一个虚拟目录,指向宿主机文件系统中的一个目录。
数据卷操作
1 | docker volume [COMMAND] |
docker volume命令是数据卷操作,根据命令后跟随command确定下一步操作
- create-创建一个volume
- inspect-显示一个或多个volume的信息
- ls-列出所有的volume
- prune-删除未使用的volume
- rm-删除一个或多个指定的volume
数据卷挂载
创建数据卷
1 | docker volume create html |
运行容器并挂载数据卷
1 | docker run --name nginx -p 8080:80 -v html:/usr/share/nginx/html -d nginx |
数据卷挂载方式:-v nameName : /targetContainerPath
如果容器运行时Volume不存在,会被自动创建出来
查看挂载目录
1 | docker volume inspect html |
修改内容
1 | vim index.html |
访问服务
目录挂载
目录挂载和数据卷挂载的语法类似:
- -v [宿主机目录]:[容器内目录]
- -v [宿主机文件]:[宿主机文件]
创建目录
1 | mkdir -p /tmp/mysql/data |
挂载/tmp/mysql/data到mysql容器内数据存储目录
挂载/tmp/mysql/conf/hmy.cnf到mysql容器的配置文件
设置MySQL密码
运行容器
1 | docker run \ |
数据卷挂载方式对比
- 数据卷挂载耦合度低,由dokcer来管理目录
- 目录挂载耦合高,需要我们自己来管理目录
Dockerfile自定义镜像
镜像结构
镜像时将应用程序及其需要的系统函数库、环境、配置、依赖打包而成
镜像是分层结构,每一层称为一个Layer
BaseImage层:包含基本的系统函数库、环境变量、文件系统
Entrypoint层:入口,是镜像中应用启动的命令
其他层:在BaseImage基础上添加依赖、安装程序、完成整个应用的安装和配置
Dockerfile
Dockerfile是一个文本文件,其中包含了一个个指令(Instruction),用指令来说明要执行什么操作来构建镜像。每一个指令都会形成一层Layer。
基于java:8-alpine镜像构建Java项目为镜像
- 新建一个空目录,在目录中新建一个文件
- 拷贝jar包到目录
- 编写Dockerfile文件
- 基于java:8-alpine作为基础镜像
- 将app.jar拷贝到镜像中
- 暴露端口
- 编写人口ENTRYPOINT
1 | # 指定基础镜像 |
- 使用docker build命令构建镜像
1 | docker build -t javaweb:1.0 . |
最后的.指从当前目录构建
- 使用docker run创建容器并运行
1 | docker run --name javaweb -p 8090:8090 -d javaweb:1.0 |
DockerCompose
Docker Compose是一个用于定义和运行多个Docker容器应用的工具,
Docker Compose可以基于Compose文件帮助我们快速部署分布式应用,而无需手动一个个创建和运行容器。
Compose使用YAML文件配置应用服务,通过指令定义集群中的每一个容器如何运行。
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 |
修改文件权限
修改文件权限为可执行
1 | chmod +x /usr/local/bin/docker-compose |
测试是否安装成功
1 | docker-compose --version |
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 |
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 | # 将宿主机的3306端口映射到容器的3306端口 |
volumes
将宿主机的文件或目录挂载到容器中(HOST:CONTAINER)
1 | # 将宿主机文件挂载到容器内 |
environment
配置环境变量
1 | environment: |
links
连接其他容器的服务(SERVICE:ALIAS)
1 | # 可以以database为域名访问服务名称为db的容器 |
Docker Compose常用命令
构建、创建、启动相关容器
1 | # -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 |
Docker网络管理命令
查看帮助文档
1 | docker network --help |
查看网络
1 | docker network ls |
创建网络
1 | docker network create |
-d 指定网络的驱动(不指定默认为bridge)
– subnet 指定子网网段(192.168.0.0/16)
– ip-range 指定容器的I范围
– gateway 子网的网关
网络删除
1 | docker network rm |
查看网络详细信息
1 | docker network inspect |
使用网络
1 | docker run/create --network |
默认情况下,docker创建或启动容器时,会默认使用名为bridge的网络
网络连接与断开
1 | docker network connect/disconnect |
单主机常见三种Docker网络类型
Docker默认情况下有bridge、host、none三种网络类型
Centos容器镜像处理
Centos安装并启用ifconfig命令
1 | yum provides ifconfig |
运行ipconfig命令
拉取centos镜像
1 | docker pull centos:centos7 |
运行centos容器并启用ifconfig命令
1 | docker run -it centos:centos7 |
从容器中创建镜像
1 | docker commit adoring_noyce centos-net |
bridge网络模式
容器默认使用的网络类型
- 宿主机上需要单独的bridge网卡,docker默认创建的是docker0
- 容器之间、容器与主机之间的网络通信是借助为每一个容器生成的一对veth pair虚拟网络设备进行通信的(一个在容器上,另一个在宿主机上)
- 每创建一个基于bridge网络的容器,都会自动在宿主机上创建一个veth*虚拟网络设备。 外部无法直接访问容器。需要建立端口映射才能访问
- 容器借由veth虚拟设备通过如docker0这种bridge网络设备进行通信
- 每一容器具有单独的IP
- bridge网络模式下宿主机与容器服务使用的端口可以重复
查看宿主机网络信息
创建桥接模式容器
1 | docker run -it centos-net #由于容器创建默认使用桥接模式,所以这里不需要使用--network指定 |
bridge网络模式下的端口映射:由于bridge网络模式的上述特点,访问bridge网络模式的设备时需要端口映射
端口映射格式
1 | docker run -p |
host网络模式
容器完全共享宿主机的网络,网络没有隔离,可以说宿主机的网络就是容器的网络
- 容器、宿主机上的应用所使用的端口不能重复
- 外部能够直接访问容器,不需要端口映射
- 容器ip就是宿主机的ip
1 | docker run -it --network=host centos-net |
none网络模式
容器上没有网络,无需任何网络设备,外部无法访问
1 | docker run -it --network=none centos-net |
只有一个本地回环lo网络设备
自定义网络
创建网络
1 | docker network create --driver bridge test |
自定义网络创建容器
1 | docker run -it --network=test centos-net |
成功分配网络内的ip地址(注意不同的网络之间是隔离的)
不同的网络是相互隔离的,无法进行通信
网络连接
1 | docker network connect test 881852a511a6 |
连接测试
1 | docker attach |
容器通信
同一网络容器通信
创建两个容器使用同一个网络,在同一个子网分配ip地址,可以相互访问
因此只要保证两个容器处于同一个网络中,就可以直接通过容器的ip地址在容器间进行通信
Docker域名解析服务器
在大多数场景下,容器部署的ip地址是自动分配的,因此无法提前知道ip地址
我们可以借助Docker提供的DNS服务器,将域名解析成对应容器的ip地址,这样就直接访问域名来实现通信(注意:域名解析只能在用户自定义网络下生效,默认网络是不行的)
1 | docker run -it --name=test01 --network=test centos-net |
容器共享网络
创建并运行一个新的容器,将其网络指定一个容器的网络,使得两个容器使用同一个网络
1 | docker run -it --name=test03 --network=container:test01 centos-net |
容器和外部通信
容器创建默认使用桥接模式,桥接模式创建一个虚拟网络,让容器在虚拟网络中,通过桥接器与外界相连。其中,数据包从容器内部的网络搭到达宿主主机再发送网络的过程最关键的是依靠NATj将地址进行转换,再利用宿主机的ip地址将数据包转发出去。
通过NAT,容器可以实现访问外界,但是当外部主动连接容器时,我们可以直接创建容器时配置端口映射
1 | docker run --name nginx -p 8080:80 -d nginx |
-p:端口映射配置,将容器对外提供访问的端口映射搭到宿主机的端口上
-p 宿主端口:容器端口
当外部访问到宿主主机的对应端口时会直接转发给容器内