容器和虚拟机的区别
- 轻量级:容器比虚拟机更轻量级,因为它们不需要模拟完整的操作系统。容器共享主机操作系统的内核,只需要运行应用程序及其相关的库和依赖项。这使得容器的启动速度更快,资源占用更少。
- 快速部署:由于容器的轻量级特性,它们可以快速部署和启动。容器可以在几秒钟内启动,而虚拟机可能需要几分钟甚至更长时间。
- 可移植性:容器具有高度的可移植性,因为它们将应用程序及其依赖项打包在一个独立的容器镜像中。这个镜像可以在不同的主机上运行,无需重新安装应用程序或其依赖项。相比之下,虚拟机需要在每个主机上安装操作系统和应用程序。
- 资源隔离:虽然容器比虚拟机更轻量级,但它们提供的资源隔离程度较低。容器共享主机操作系统的内核,因此它们可能会受到其他容器或主机系统的影响。相比之下,虚拟机提供了更高级别的资源隔离,因为它们模拟了一个完整的操作系统。
- 应用程序兼容性:由于容器共享主机操作系统的内核,它们通常与应用程序的兼容性更好。应用程序可以直接在容器中运行,无需进行任何修改。相比之下,虚拟机需要模拟一个完整的操作系统,这可能会导致应用程序的兼容性问题。
镜像
Docker 镜像 (lmage) 就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。它也相当于是一个 root 文件系统。比如官方镜像 centos 7 就包含了完整的一套 centos 7 最小系统的 root 文件系统。相当于容器的源代码,docker 镜像文件类似于 Java 的类模板,而 docker 容器实例类似于 Java 中 new 出来的实例对象。
容器
-
从面向对象角度
Docker 利用容器 (Container) 独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。就像是Java是镜像运行时的实体和实例对象一样,镜像是静态的定义,容器是镜像运行时的实体,容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。
-
从镜像容器角度
可以把容器看做是一个简易版的 Linux 环境(包舌root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
仓库
集中存放镜像的地方,仓库分为公开仓库 (Public) 和私有仓库 (Private) 两种形式。最大的公开仓库是 Docker Hub (hub.docker.com/) 存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云 、网易云等
基本运行流程
- 用户是使用 Docker Client与 Docker Daemon 建立通信,并发送请求给后者;
- Docker Daemon 作为 Docker 架构中的主体部分,首先提供 Docker Server 的功能使其可以接受 Docker Cient 的请求;
- Docker Engine(引擎) 执行 Docker 内部的一系列工作,每一项工作都是以一个 Job 的形式的存在;
- Job 的运行过程中,当需要容器镜像时,则从 Docker Registy 中下载像,并通过镜像管理驱动将下载镜像以 Graph 的形式存储;
- 当需要为 Docker 创建网络环境时,通过网络管理驱动创建并配置 Docker 容器网络环境;
- 当需要限制 Docker 容器运行资源或执行用户指令等操作时,则通过 Exec Driver 来完成;
- Libcontainer 是一项独立的容器管理包,Network Driver 以及 Exec Diver 都是通过 Libcontainer 来实现具体对容器进行的操作。
安装 Docker
安装 GCC
yum -y install gcc
安装 GCC-C++
yum -y install gcc-c++
安装 yum-utils
yum -y install yum-utils
设定本地仓库
yum -config -manager -- add -repo http://mirrors.aliyun.com/docker- ce/linux/centos/docker- ce.repo
更新 yum 软件包索引
yum makecache fast
安装 Docker CE
yum -y install docker-ce docker-ce-cli containerd.io
启动 Docker
systemctl start docker
查看 Docker 进程
ps -ef | grep docker
阿里云镜像加速配置
- 登录阿里云,找到容器镜像服务
- 创建实例
- 镜像工具 -- 镜像加速器 -- 复制加速器地址
- 根据阿里云文档进行命令操作
常用命令
帮助启动类命令
- 启动:
systemctl start docker - 停止:
systemctl stop docker - 重启:
systemctl restart docker - 查看状态:
systemctl status docker - 开机自启:
systemctl enable docker
镜像命令
- 列出主机上的镜像:
docker images - 查找仓库镜像:
docker search 镜像名称 - 下载镜像:
docker pull 镜像名称:TAG - 查看镜像/容器/数据所占的空间:
docker system df - 删除镜像::
docker rmi 镜像名字或镜像ID
容器命令
- 新建 + 启动容器
docker run [OPTIONS]
OPTIONS:
--name:为容器指定一个新名称
-d:后台运行容器并返回容器 ID,即启动守护式容器(后台运行)
-i:以交互式运行容器,通常与 -t 同时使用
-t:为容器分配一个伪终端,通常与 -i 同时使用
-P:随机端口映射
-p:指定端口映射
举例:
创建CentOS容器,并进入终端:docker run -it centos /bin/bash
80 端口映射到容器的 8080 端口:docker run -p 80:8080 nginx
PS:Docker 容器后台运行,就必须有一个前台进程,容器运行的命令如果不是那些一直挂起的命令(比如运行 top,tail) ,就是会自动退出的。
- 列出当前所有正在运行的容器:
docker ps - 退出容器:1、exit 退出,容器停止;2、ctrl + p + q 退出,容器不停止;
- 启动已经停止运行的容器:
docker start 容器名字或容器 ID - 重启容器:
docker restart 容器名字或容器 ID - 停止容器:
docker stop 容器名字或容器 IDD - 强制停止容器:
docker kill 容器名字或容器 ID - 删除已停止的容器:
docker rm 容器 ID - 查看容器日志:
docker logs 容器 ID - 查看容器内运行的进程:
docker top 容器 ID、docker ps 容器 ID - 查看容器内部细节:
docker inspect 容器 ID - 进入正在运行的容器并以命令行交互:
docker exec -it 容器 ID /bin/bashdocker attach 容器 ID- exec 和 attach区别
- attach 直接进入容器启动命令的终端,不会启动新的进程,用 exit 退出,会导致容器的停止;
- exec 是在容器中打开新的终端,并且可以启动新的进程,用 exit 退出,不会导致容器的停止
- 容器内拷贝文件到主机上:
docker cp 容器 ID:容器内路径 目的主机路径 - 容器导出到主机;
docker export 容器 ID > 文件名.tar - 主机容器导入;
cat 文件名.tar | docker import -镜像用户/镜像名:镜像版本号
Docker 镜像
什么是镜像
是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,只有通过镜像文件才能生成 Docker 容器实例。
UnionFS 联合文件系统
是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来。
Docker 镜像分层
Docker 的镜像实际上由一层一层的文件系统组成,这种层级的文件系统 UnionFS。镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。Docker 镜像层都是只读的,容器层是可写的。
Docker 中的镜像分层,支持通过扩展现有镜像,创建新的镜像。类似 Java 继承于一个 Base 基础类,自己再按需扩展。
新镜像是从 Base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
Docker Commit
docker commit提交容器副本使之成为一个新的镜像,比如说从 Docker Pull 下来的原始的默认 Ubuntu 镜像是不带着 vim 命令的,可以安装 vim 命令后,生成新的镜像。
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:版本号
Docker 私有仓库
- 拉取私服镜像:
docker pull registry - 运行私服镜像:
docker run -d -p 5000:5000 -v /user/myregistry/:/tmp/registry -- privileged=true registry,默认情况,仓库被创建在容器的/var/ib/registry目录下,建议自行用容器卷映射,方便于宿主机联调 - curl验证私服库上有什么镜像:
curl -XGET http://ip:5000/v2/_catalog - 将新镜像修改成符合私服规范的 tag:
docker tag 镜像名:tag ip:5000/镜像名:tag - 修改配置文件使之支持 http:
vim /etc/docker/daemon.json
在 json 串里追加:
"insecure- registries" : ["ip:5000""]
注意:地址和端口改成自己的,如果改完不生效,重启 Docker 即可
- 推送到私服:
docker push ip:5000/镜像名:版本号 - pull 到本地并运行:
docker pull ip:5000/镜像名:版本号
Docker 挂载目录
如果出现 cannot open directory.:Permission denied,解决办法: 在挂载目录后多加一个 --privileged=true 参数即可
Docker 容器数据卷
卷就是目录或文件,存在于一个或多个容器中,由 Docker 挂载到容器,但不属于联合文件系统,因此能够绕过 Union File System 提供一些用于持续存储或共享数据的特性,卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此 Docker 不会在容器删除时删除其挂载的数据卷,一句话:有点类似 Redis 里面的 rdb 和 aof 文件,将 docker 容器内的数据保存进宿主机的磁盘中
将运行的环境打包镜像,run 后形成容器实例运行 ,但是需要对数据的要求希望是持久化的,docker 容器产生的数据,如果不备份,那么当容器实例删除后,突器内的数据自然也就没有了
命令
- 运行一个带有容器卷存储功能的容器实例:
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:XX 镜像名,XX 为读或者读写,参数为ro(只读)或rw(读写),默认为rw - 查看数据卷是否挂载成功:
docker inspect 容器ID,查看 Mounts 节点信息 - 容器 2 继承容器 1 的卷规则:
docker run -it --privileged=true --volumes-from 父类容器名称 --name u2 ubuntu
Docker File
Docker File 是用来构建 Docker 镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
构建三步骤
- 编写 Docker File 文件
- docker build 命令构建镜像
- dicker run 镜像运行容器实例
Docker 执行 Docker File 的大致流程
- docker 从基础镜像运行一个容器
- 执行一条指令并对容器做出修改
- 执行类似 docker commit 的操作提交一个新的镜像层
- docker 再基于刚提交的镜像运行一个新容器
- 执行 docker file 中的下一条指令直到所有指令都执行完成
docker file 面向开发,docker 镜像成为交付标准,docker 容器则涉及部署与运维,三者缺一不可,合力充当 docker 体系的基石。
Docker File 关键保留字
- FROM:基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是 FROM
- MAINTAINER:镜像维护者的姓名和邮箱地址
- RUN:容器构建时需要运行的命令,RUN 是在 docker build时运行,两种格式:shell 和 exec
- EXPOSE:当前容器对外暴露出的端口
- WORKDIR:指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
- USER:指定该镜像以什么样的用户去执行,如果都不指定,默认是 root
- ENV:用来在构建镜像过程中设置环境变量
- ADD:将宿主机目录下的文件拷贝进镜像且会自动处理 URL 和解压 tar 压缩包
- COPY:类似 ADD,拷贝文件和目录到镜像中
- VOLUME:容器数据卷,用于数据保存和持久化工作
- CMD:指定容器启动后的要干的事情,Docker file 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换,CMD 是在docker run 时运行。
- ENTRYPOINT:用来指定一个容器启动时要运行的命令,类似于 CMD 指令,但是 ENTRYPOINT 不会被 docker run 后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序,在执行docker run的时候可以指 ENTRYPOINT 运行所需的参数,如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
虚悬镜像
仓库名、标签都是 none 的镜像,虚悬镜像已经失去存在价值,可以删除
删除虚悬镜像命令:docker image prune
Docker 网络
docker 启动后,会产生一个名为docker0的虚拟网桥
Docker 网络作用
- 容器间的互联和通信以及端口映射
- 容器IP变动时候可以通过服务名直接网络通信而不受到影响
Docker 网络模式
- bridge 模式:使用 --network bridge 指定,默认使用 docker0,为每一个容器分配、设置 IP 等,并将容器连接到一个 docker0,虚拟网桥,默认为该模式;
- host 模式:使用 --network host 指定,,容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口;
- none 模式:使用 --network none 指定容器有独立的 Network namespace,但并没有对其进行任何网络设置,如分配 veth pair 和网桥连接,IP 等;
- container 模式:使用 --network container:NAME 或者容器 ID 指定,新创建的容器不会创建自己的网卡和配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等;
常用命令
- 查看网络:
docker network ls - 查看网络源数据:
docker network inspect XX - 删除网络:
docker network rm XX - 创建网络:
docker network create XX
Docker 容器编排
Compose
Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。需要定义一个 YAML 格式的配置文件 docker-compose.yml,写好多个容器之间的调用关系。然后只要一个命令,就能同时启动/关闭这些容器
Compose 允许用户通过一个单独的 docker-compose.yml 模板文件来定义一组相关联的应用容器为一个项目。
可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。
安装步骤
// 第一步:下载
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
// 第二步:授权
chmod +x /usr/local/bin/docker-compose
// 第三步:通过查看版本验证是否安装成功
docker-compose --version
使用步骤
- 编写 Dockerfile 定义各个微服务应用并构建出对应的镜像文件
- 使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。
- 最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线
Docker Portainer
Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理 Docker 环境,包括单机环境和集群环境。
安装步骤
docker run
-d
-p 8000:8000
-p 9000:9000
--name portainer
--restart=always
-v /var/run/docker.sock:/var/run/docker.sock
-v portainer_data:/data
portainer/portainer
// 第一次登录需创建 admin,访问地址:xxx.xxx.xxx.xxx:9000
Docker 容器监控
Docker 的容器监控就是 CAdvisor 监控收集 + InfluxDB 存储数据 + Granfana 展示图表
安装步骤
-
新建目录:
mkdir /mydocker/cig -
新建 docker-compose.yml
version: '3.1'
volumes:
grafana_data: {}
services:
influxdb:
image: tutum/influxdb:0.9
restart: always
environment:
- PRE_CREATE_DB=cadvisor
ports:
- "8083:8083"
- "8086:8086"
volumes:
- ./data/influxdb:/data
cadvisor:
image: google/cadvisor
links:
- influxdb:influxsrv
command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
restart: always
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
grafana:
user: "104"
image: grafana/grafana
user: "104"
restart: always
links:
- influxdb:influxsrv
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
environment:
- HTTP_USER=admin
- HTTP_PASS=admin
- INFLUXDB_HOST=influxsrv
- INFLUXDB_PORT=8086
- INFLUXDB_NAME=cadvisor
- INFLUXDB_USER=root
- INFLUXDB_PASS=root
- 启动 docker-compose 文件:
docker-compose up - 查看三件套是否启动成功:
docker ps - 浏览 cAdvisor 收集服务,http://ip:8080/
- 浏览 influxdb 存储服务,http://ip:8083/
- 浏览 grafana 展现服务,http://ip:3000 ,默认帐户密码(admin/admin)
通过 Docker 部署项目
通过 Dockerfile 部署到容器
- 项目打包成 jar
- 编写 Dockerfile
# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER zzyy
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为zzyy_docker.jar
ADD docker_boot-0.0.1-SNAPSHOT.jar zzyy_docker.jar
# 运行jar包
RUN bash -c 'touch /zzyy_docker.jar'
ENTRYPOINT ["java","-jar","/zzyy_docker.jar"]
#暴露6001端口作为微服务
EXPOSE 6001
- 将微服务 jar 包和 Dockerfile 文件上传到同一个目录下/mydocker
- 构建镜像:
docker build -t zzyy_docker:1.6 . - 运行容器:
docker run -d -p 6001:6001 zzyy_docker:1.6
通过 Docker-Compose 部署到容器
- 编写 docker-compose.yml 文件
version: "3"
services:
microService:
image: zzyy_docker:1.6
container_name: ms01
ports:
- "6001:6001"
volumes:
- /app/microService:/data
networks:
- atguigu_net
depends_on:
- redis
- mysql
redis:
image: redis:6.0.8
ports:
- "6379:6379"
volumes:
- /app/redis/redis.conf:/etc/redis/redis.conf
- /app/redis/data:/data
networks:
- atguigu_net
command: redis-server /etc/redis/redis.conf
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: '123456'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_DATABASE: 'db2021'
MYSQL_USER: 'zzyy'
MYSQL_PASSWORD: 'zzyy123'
ports:
- "3306:3306"
volumes:
- /app/mysql/db:/var/lib/mysql
- /app/mysql/conf/my.cnf:/etc/my.cnf
- /app/mysql/init:/docker-entrypoint-initdb.d
networks:
- atguigu_net
command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
networks:
atguigu_net:
- 修改jar 里的 yml配置文件,把数据库等连接地址改为通过服务名访问
- mvn package 命令将微服务形成新的 jar 包,并上传到服务器 /mydocker 目录下
- 编写 Dockerfile
# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER zzyy
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为zzyy_docker.jar
ADD docker_boot-0.0.1-SNAPSHOT.jar zzyy_docker.jar
# 运行jar包
RUN bash -c 'touch /zzyy_docker.jar'
ENTRYPOINT ["java","-jar","/zzyy_docker.jar"]
#暴露6001端口作为微服务
EXPOSE 6001
- 构建镜像:
docker build -t zzyy_docker:1.6 . - 执行命令:
docker-compose up -d