阿里云-Docker的使用
1. 基本知识
1.1 Docker核心概念
1.1.1 镜像(Image)
- 定义:镜像是一个只读的模板,包含了运行应用所需的所有内容,如代码、运行时、库文件、环境变量和配置文件等。可以把镜像理解为“容器的快照”或“应用的安装包”。
- 特点:
- 只读性:镜像本身是只读的,不能直接修改。
- 分层存储:由多个层组成,每一层代表一次修改,这种分层结构使得镜像的构建和存储更加高效,因为只有发生变化的层才会被重新构建和存储。
- 可复用性:同一个镜像可以创建多个容器实例。
- 版本管理:通过标签(tag)进行版本管理,方便追踪和管理。
- 作用:是创建容器的基础,通过镜像可以快速实例化多个容器。
1.1.2 容器(Container)
- 定义:容器是镜像的运行实例,是一个轻量级、可移植的执行环境。它共享主机操作系统的内核,但彼此独立,拥有自己的文件系统、网络和进程空间。
- 特点:
- 隔离性:每个容器都有自己独立的文件系统、网络和进程空间,相互之间不会产生干扰。
- 临时性:容器可以被创建、启动、停止、删除等操作。
- 可写层:在镜像基础上添加了一个可写层,用于存储容器运行时产生的数据。
- 进程级:容器内通常运行一个主进程。
- 作用:可移植、启动迅速,适合弹性扩展,用于运行应用程序。
1.1.3 仓库(Repository)
- 定义:仓库是用于存储和分发Docker镜像的地方,可以包含一个镜像的多个版本。
- 分类:
- 公共仓库:如Docker Hub,上面有大量的官方和社区共享的镜像,用户可以自由上传和下载镜像。
- 私有仓库:企业或个人可以搭建自己的私有仓库,用于内部使用,以满足安全和定制化需求。
- 作用:提供镜像的存储、分发和共享功能。
1.1.4 Dockerfile
- 定义:Dockerfile是一种文本文件,用于定义Docker镜像的构建过程。它包含了一系列的指令,用于指定基础镜像、安装软件、拷贝文件、配置环境等。
- 作用:自动化构建镜像,确保开发、测试和生产环境一致。通过编写Dockerfile,可以精确地控制镜像的构建过程,保证镜像的一致性和可重复性。
1.1.5 Docker引擎(Docker Engine)
- 定义:Docker的核心组件,用于创建和管理容器。分为社区版(CE)和企业版(EE)。
- 组成:
- 服务端(daemon):运行在主机上,负责接收和处理命令,管理镜像、容器、网络与数据卷等。
- 客户端(CLI):用户与Docker交互的命令行工具,通过发送API请求给服务端来执行各种操作。
- REST API:供第三方工具或系统与Docker集成,实现更高级的自动化操作。
- 作用:提供容器的运行时和API,是Docker实现各种功能的基础。
2. ECS中安装Docker
安装dokcer
https://help.aliyun.com/zh/ecs/use-cases/install-and-use-docker
执行以下命令安装Docker社区版本
#添加Docker软件包源
sudo wget -O /etc/yum.repos.d/docker-ce.repo http://mirrors.cloud.aliyuncs.com/docker-ce/linux/centos/docker-ce.repo
sudo sed -i 's|https://mirrors.aliyun.com|http://mirrors.cloud.aliyuncs.com|g' /etc/yum.repos.d/docker-ce.repo
#Alibaba Cloud Linux3专用的dnf源兼容插件
sudo dnf -y install dnf-plugin-releasever-adapter --repo alinux3-plus
#安装Docker社区版本,容器运行时containerd.io,以及Docker构建和Compose插件
sudo dnf -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
#启动Docker
sudo systemctl start docker
#设置Docker守护进程在系统启动时自动启动
sudo systemctl enable docker
通过查看Docker版本命令,验证Docker是否安装成功。
sudo docker -v
配置镜像源
docker hub无法连接,使用加速器
https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
# 创建文件夹(该文件夹可能已经存在)
sudo mkdir -p /etc/docker# tee:将标准输入写入文件并输出到标准输出
sudo tee /etc/docker/daemon.json <<-'EOF'
{"registry-mirrors": ["https://*****.mirror.aliyuncs.com"]
}
EOFsudo systemctl daemon-reload
sudo systemctl restart docker
<<-'EOF'
...EOF
- 这是 Here Document 语法,用于将多行内容作为输入
-
表示忽略行首的制表符(tab),保持格式整洁EOF
是结束标记(可以是任意字符串)镜像源配置不适用于
docker search
命令,因为它直接查询Docker Hub
案例:运行nginx镜像
拉取镜像
sudo docker pull nginx:latest
修改nginx的首页
#创建Dockerfile设置Nginx作为基础镜像,并在Web服务器的根目录创建一个显示Hello World!的index.html文件。
sudo tee Dockerfile <<-'EOF'
FROM nginx:latest
RUN echo 'Hello World!' > /usr/share/nginx/html/index.html
EOF
构建镜像
#构建镜像,镜像名称为hello-world
sudo docker build . -t hello-world:latest
启动nginx镜像
启动Web程序镜像的容器,并且命名容器名称为hello-world
。
sudo docker run -d -p 81:80 --name hello-world hello-world:latest
81:80 端口映射, 81: linux的端口,80:容器运行的端口
hello-world:latest hello-world为镜像名称, latest为该镜像的tag
访问测试
使用此ecs本地访问测试
使用其他浏览器访问此时
81端口要添加到防火墙白名单
3.操作
镜像管理
检索镜像 docker search
docker的镜像地址,可以用国内的镜像代替
https://hub.docker.com
# 镜像源为 docker hub 可以使用
docker search nginx
name:镜像名
stars:使用认识
official:是否是官方的
下载镜像 docker pull
#拉取Nginx镜像 nginx:镜像名,latest:nginx的tag(标识最新的tag版本)
sudo docker pull nginx:latest
如果没有执行
列表展示 docker images
# 展示ecs中已下载的docker镜像
docker images
REPOSITORY: 镜像名称
TAG:标签(版本)
IMAGE ID :唯一标识id
CREATED: 创建时间
SIZE: 镜像大小
删除镜像 docker rmi
方式一:
# nginx:lastest 镜像名称:tag标签
docker rmi nginx:lastest
方式二:
# 605: imageId 的前缀,不用写全,只要写到能识别唯一的就行
docker rmi 605
提交镜像 docker commit
docker commit -m "commit test" hello-world my-nginx-hello-world:v0.0.1
- -m: 提交的message信息
- hello-world: 容器的名称
- my-nginx-hello-world:打包后的镜像名称
保存镜像 docker save
目的:将镜像打包成tar文件,方便线下传输(如不方便通过镜像拉取时,需要先打包发给客户,然后再加载镜像)
docker save -o my-nginx-hello-world.tar my-nginx-hello-world:v0.0.1
-o(或 --output) 参数用于指定导出镜像的保存路径和文件名。没有文件路径表示当前目录
如: -o /tmp/backup/nginx.tar
加载镜像 docker load
目的:将tar文件load成镜像
docker load -i my-nginx-hello-world.tar
-i 指定tar包所在的路径
推送镜像 docker push
阿里云镜像仓库
忘记密码的,可以退出登录找回密码
登录仓库 docker login
镜像命名 docker tag
推送到仓库 docker push
构建镜像 docker build
目的:将spring boot项目,利用dockerfile打包成可直接运行的镜像
# 构件命令
docker build -t myDocker:v0.0.1 -f Dockerfile .
1.linux中创建dockerfile文件、可运行的jar包
1.1 在spring boot中处理好jar包、Dockerfile文件,并上传到
(Dockerfile文件中指令的作用请参考 Dockerfile 详解)
2.使用build、dockerfile构件镜像
docker build -t myboot:v0.0.1 -f Dockerfile .
docker build
: 根据指定的 Dockerfile 创建一个新的镜像-t
或--tag
:为构建的镜像指定名称和标签myboot
:镜像名称(通常是小写字母)v0.0.1
:镜像标签(通常表示版本号)-f
或--file
:指定 Dockerfile 文件的路径Dockerfile
:构建使用的 Dockerfile 文件名(如果不指定-f
,默认使用当前目录的Dockerfile)
.
(最后的点) 指定构建上下文(build context)
含义:当前目录
重要性:Docker 会将此目录下的所有文件发送给 Docker 守护进程(daemon)用于构建,Dockerfile 中的
COPY
或ADD
只能操作此目录下的文件- 命令执行流程
Docker 客户端读取
Dockerfile
文件将当前目录(
.
)作为构建上下文发送给 Docker 守护进程按照
Dockerfile
中的指令逐步构建镜像最终生成名为
myboot
、标签为v0.0.1
的镜像
3. 启动镜像
docker run -d -p 8081:8080 --name myboot myboot:v0.0.1
4.测试
测试uri为:arms/cpu/1
本地调用、浏览器调用测试都通过
容器管理
启动容器 docker run
# 启动容器
sudo docker run -d -p 81:80 --name hello-world hello-world:latest
- sudo:以超级管理员权限执行命令
- -d:以后台(守护)模式运行容器
- -p 81:80 端口映射(linux的81端口,映射到容器内的80端口,在浏览器就可以通过81端口访问容器)
- --name hello-world: 容器名称
- hello-world:latest :镜像名称+tag版本
查看容器 docker ps
# 查看运行中容器
docker ps#查看所有的容器(包含已经停止的)
docker ps -a
CONTAINER ID : 运行的容器id
IMAGE : 镜像名
COMMAND
CREATED :运行的时间段
STATUS :运行的状态 Up 表示 运行的容器;Exited停止的容器
PORTS : 容器运行的端口号(容器内的端口号,需要一个外部的端口号做映射才能访问)
NAMES : 应用容器的名称(不写会随机一个,建议写)
停止容器 docker stop
# 5522 为 容器的id前缀
docker stop 5522
启动容器 docker start
docker start 5522
重启容器 docker restart
docker restart 5522
无论是停止运行,还是正在运行的,都会重启
容器状态 docker stats
查看内存、CPU的占用
docker stats 5522
容器日志 docker logs
docker logs 5522
进入容器 docker exec
docker exec 在正在运行的容器中执行命令
# 进入容器内的控制台
docker exec -it hello-world bash
exit 退出容器
删除容器 docker rm
# hello-world 为容器的名称(不是镜像的名称)。 也可以写容器的id
docker rm hello-world# 强制删除(包括正在运行额)
docker rm -f hello-world
目录挂载、卷映射
问题:容器内需要变更的配置、保存的日志文件等,如果仅保存在容器内,在容器重启、下线后会丢失数据,因此要放到容器外面
目录挂载
docker run -d -p 81:80 -v /app/nghtml:/usr/share/nginx/html --name app01 nginx:latest
- -d 后台运行
- -p 81:80 端口映射
- -v /app/nghtml:/usr/share/nginx/html app/nghtml linux的文件 /usr/share/nginx/html 容器内的文件路径(这2个都是文件夹路径)
- --name app01 容器名称
- nginx:latest 镜像
/usr/share/nginx/html 文件
在app/nghtml中创建index.html,并访问
卷映射
docker启动指令
docker run -d -p 81:80 \
-v /app/nghtml:/usr/share/nginx/html \
-v ngconf:/etc/nginx \
--name app02 nginx:latest
-v /app/nghtml:/usr/share/nginx/html 目录挂载
-v ngconf:/etc/nginx \ ngconf前没有 "/",表示卷, 带 "/" 表示目录挂载
查询所有的卷
docker volume ls
查询卷的位置 /var/lib/docker/volumes 是所有卷的默认位置
容器间相互访问
问题:同一个linux下,有多个容器,容器间如何直接访问,而不是先绕到外部的机器端口?
最慢:公网ip:端口号
中速:内网ip:端口号
快速:容器直接访问
方案一:通过容器ip+容器端口号 访问
docker自身有维护了一个默认网络 docker0,会对各个容器分配ip。
1. 开启2个容器
# 启动容器1
docker run -d -p 81:80 \
-v /app/nghtml:/usr/share/nginx/html \
-v ngconf:/etc/nginx \
--name app01 nginx:latest # 启动容器2
docker run -d -p 82:80 \
-v /app/nghtml:/usr/share/nginx/html \
-v ngconf:/etc/nginx \
--name app02 nginx:latest
1.1 容器app01的ip
docker inspect app01
默认gateway 172.17.0.1,分配的ip为 172.17.0.2
1.2 容器app02的ip为172.17.0.2
2. 进入容器app01访问容器app02
验证成功,可以直接通过容器ip+容器端口访问
问题:无法通过容器名称访问
思考:容器重启后,容器内部分配的ip会变化,如何解决?
解决方案:使用方案二的自定义网络,通过容器名称访问解决
方案二:通过容器名称访问
1. 自定义创建网络 mynet
容器的名称作为域名,然后通过域名访问
docker network create mynet
2.启动容器时挂载mynet网络
# 启动app01
docker run -d -p 81:80 \
-v /app/nghtml:/usr/share/nginx/html \
-v ngconf:/etc/nginx \
--network mynet \
--name app01 nginx:latest # 启动app02
docker run -d -p 82:80 \
-v /app/nghtml:/usr/share/nginx/html \
-v ngconf:/etc/nginx \
--network mynet \
--name app02 nginx:latest
--network mynet 挂载自定义的网络mynet
3.进入容器app01,通过域名访问容器app02
验证通过可以通过容器名称访问
查看容器app01的ip
gateway 从127.17 变为了127.18
其他指令
强制删除所有运行中的容器
docker rm -f $(docker ps -aq )
- 编辑文件 vi
- 查看文件 cat
Docker Compose
如果您参考的本文安装Docker,那么Compose插件将默认安装到您的实例中。您可以通过如下命令查看。
sudo docker compose version
案例
案例1:打包镜像为tar包客户,客户使用docker运行
1.将镜像打包
docker commit -m "commit test" hello-world my-nginx-hello-world:v0.0.1
在使用运行命令运行即可
案例2:构件redis的主从同步集群
1.下载镜像
docker pull bitnami/redis
2. 主机
创建redis数据目录,并修改权限
mkdir /app/rd1
chmod -R 777 /app/rd1
启动主机
#创建redis数据目录,并修改权限
mkdir /app/rd1
chmod -R 777 /app/rd1# 启动容器
docker run -d \
-p 6379:6379 \
-v /app/rd1:/bitnami/redis/data \
-e REDIS_REPLICATION_MODE=master \
-e REDIS_PASSWORD=123456 \
--network=mynet \
--name redis01 \
bitnami/redis
3.启动从机
docker run -d -p 6380:6379 -v /app/rd2:/bitnami/redis/data -e REDIS_REPLICATION_MODE=slave -e REDIS_MASTER_HOST=redis01 -e REDIS_MASTER_PORT=6379 -e REDIS_MASTER_PASSWORD=123456 -e REDIS_PASSWORD=123456 --network=mynet --name redis02 bitnami/redis
-e REDIS_MASTER_HOST=redis01 \ #通过容器名称访问主机
4.结果:
案例3:构建spring boot项目的镜像
参考:构建镜像章节