docker学习(附:安装mysql,redis)
docker学习(附:安装mysql,redis)
Pei本人白天空闲时看b站尚硅谷docker 2022版教程所记的笔记,笔记内容来源于视频中老师的文档内容,晚上会抽空整理至此博客上。
安装步骤
卸载旧版本
1 | yum remove docker \ |
yum安装gcc相关
1 | yum -y install gcc |
安装需要的软件包
1 | yum install -y yum-utils |
设置stable镜像仓库
注意:国内由于众所周知的原因,网速可能会特别慢,这个可以使用阿里云仓库替换
1 | yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo |
替换为
1 | yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo |
更新yum软件包索引
1 | yum makecache fast |
安装docker ce
1 | yum install docker-ce docker-ce-cli containerd.io |
启动docker
启动docker服务
1 | systemctl start docker |
查看是否成功运行
1 | ps -ef|grep docker |
测试
查看docker版本
1 | docker version |
hello-world
1 | docker run hello-world |
卸载
1 | systemctl stop docker |
阿里云容器镜像加速
https://promotion.aliyun.com/ntms/act/kubernetes.html
控制台(右上角)-产品与服务(左侧菜单)-弹性计算-容器镜像服务-镜像工具-镜像加速器
如上图,弹性计算中的容器镜像服务
执行下方命令即可。
永远的hello-world
1 | docker run hello-world |
run都做了什么,看下图
底层原理
- docker有着比虚拟机更少的抽象层
由于docker不需要Hypervisor(虚拟机)实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势 - docker利用的是宿主机的内核,而不需要加载操作系统OS内核
当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。进而避免引寻、加载操作系统内核返回等比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载OS,返回新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个docker容器只需要几秒钟。
docker | 虚拟机(VM) | |
---|---|---|
操作系统 | 与宿主机共享OS | 宿主机OS上运行虚拟机OS |
存储大小 | 镜像小、便于存储与传输 | 镜像庞大(vmdk、vdi等) |
运行性能 | 几乎无额外性能损失 | 操作系统额外的CPU、内存消耗 |
移植性 | 轻便、灵活、适应于Linux | 笨重,与虚拟化技术耦合度高 |
硬件亲和性 | 面向软件开发者 | 面向硬件运维者 |
部署速度 | 快速、秒级 | 较慢,10s以上 |
Docker常用命令
帮助启动类命令
启动docker:systemctl start docker
停止docker:systemctl stop docker
重启docker:systemctl restart docker
查看docker状态:systemctl status docker
开机启动:systemctl enable docker
查看docker概要信息:docker info
查看docker总体帮助文档:docker –help
查看docker命令帮助文档:docker 具体命令 –help
镜像命令
docker images
说明:列出本地主机上的镜像
各个字段说明:
REPOSITORY | TAG | IMAGE_ID | CREATED | SIZE |
---|---|---|---|---|
镜像的仓库源 | 镜像的标签版本号 | 镜像ID | 镜像创建时间 | 镜像大小 |
同一仓库源可以有多个TAG版本,代表这个仓库源的不同个版本,我们使用REPOSITORY:TAG来定义不同的镜像。如果你不指定一个镜像的版本标签,例如你只使用ubuntu,docker将默认使用ubuntu:latest镜像
OPTIONS说明:
-a:列出本地所有的镜像(含历史镜像)
-q:只显示镜像ID
例:
docker images -a
docker images -q
docker images -aq
docker search 某个xxx镜像名字
例:docker search redis
各个字段说明:
NAME | DESCRIPTION | STARTS | OFFICIAL | AUTOMATED |
---|---|---|---|---|
镜像名称 | 镜像说明 | 数量 | 是否是官方的 | 是否是自动构建的 |
OPTIONS说明:
–limit N:只列出前N条
例:docker search –limit 5 redis
docker pull 某个xxx镜像名字
下载镜像
docker pull 镜像名字[:TAG]
docker pull 镜像名字:没有TAG就是最新版,等价于 docker pull 镜像名字[:latest]
例:
docker pull redis 等价于 docker pull redis:latest
docker pull redis:6.0.8
docker system df: 查看镜像/容器/数据卷所占的空间
docker rmi
删除镜像
-f:强制删除
删除多个:docker rmi -f 镜像名字1:TAG 镜像名字2:TAG
删除单个:docker rmi -f 镜像id
删除全部(参数续传):docker rmi -f $(docker images -qa)
例:
docker rmi -f redis
docker rmi -f feb5aw8ab7
docker rmi -f $(docker images -qa)
面试题:谈谈docker虚悬镜像是什么?
仓库名、标签都是<none>的镜像,俗称虚悬镜像(dangling image)
查询所有虚悬镜像:docker image ls -f dangling=true
删除虚悬镜像:docker image prune
思考
结合我们Git的学习,大家猜猜是否会有 docker commit/docker push?
容器命令
新建+启动命令
1 | docker run [OPTIONS] IMAGE [COMMAND] [ARG...] |
OPTIONS说明(常用):有些是一个减号,有些是两个减号
–name=容器新名字:为容器指定一个名称
-d:后台运行容器并返回容器ID,也即启动守护式容器(后台运行)
-i:以交互模式运行容器,通常与-t同时使用
-t:为容器重新分配一个伪输入终端,通常与-i同时使用
也即启动交互式容器(前台有伪终端/命令窗口,等待交互)
例:
docker run -it ubuntu /bin/bash
docker run -it –name=myu1 ubuntu /bin/bash
/bin/bash:放在镜像名后的是命令,这里我们希望有个交互式shell,因此使用的是/bin/bash,默认也是,要退出终端(容器的命令窗口),直接输入exit
个人理解:相当于使用docker创建了一个ubuntu的linux机容器,在容器中常用的linux命令也都可以用
-P:随机端口映射,大写P
-p:指定端口映射,小写p
参数 | 说明 |
---|---|
-p hostPort:containerPort | 端口映射-p 8080:80 |
-p ip:hostPort:containerPort | 配置监听地址-p 10.0.0.100:8080:80 |
-p ip:containerPort | 随机分配端口-p 10.0.0.100:80 |
-p hostPort:containerPort:udp | 指定协议-p 8080:80:tcp |
-p 81:80 -p 443:443 | 指定多个 |
列出当前所有正在运行的容器
docker ps [OPTIONS]
-a:列出当前所有正在运行的容器+历史上运行过的
-l:显示最近创建的容器
-n 数量N:显示最近N个创建的容器
-q:静默模式,只显示容器编号
STATUS:Up表示正在运行
退出容器
两种退出方式
exit:run进去容器,exit退出,容器停止
ctrl+p+q:run进去容器,ctrl+p+q退出,容器不停止
启动已经停止运行的容器
docker start 容器ID或者容器名
重启容器
docker start 容器ID或者容器名
停止容器
docker restart 容器ID或者容器名
强制停止容器
docker kill 容器ID或者容器名
删除已停止的容器
docker rm 容器ID
强制删除:docker rm -f 容器ID
一次性删除多个容器实例:
docker rm -f $(docker ps -a -q)
docker ps -a -q|xargs docker rm
以下是重要指令
启动守护式容器(后台服务器)
在大部分场景,我们希望docker的服务是后台运行的,我们可以通过-d指定容器的后台运行模式。
docker run -d 容器名
假设使用docker run -d centos启动了一个容器
问题:使用docker ps -a进行查看,会发现容器已经退出
很重要的说明一点:Docker容器后台运行,就必须有一个前台进程。
容器运行的命令如果不是那些一直挂起的命令(top,tail),就是会自动退出的。
这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,我们配置启动服务只需要启动响应的service即可。例如service nginx start,但是,这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用,这样的容器后台启动后,会立即自杀,因为他觉得没事可做了。
所以,最佳的解决是,将你要运行的程序以前台进程的形式运行,常见的就是命令行模式,表示我还有交互操作,别中断,O(∩_∩)O哈哈~
- redis前后台启动演示case
- 前台交互式启动
- docker run -it redis
- 后台守护式启动
- docker run -d redis
- 前台交互式启动
查看容器日志
docker logs 容器id
查看容器内运行的进程
docker top 容器id
查看容器内部细节
docker inspect 容器id
进入正在运行的容器并以命令行交互
1 | docker exec -it 容器id /bin/bash |
1 | docker attach 容器id |
上述两个区别:
attach直接进入容器启动命令的终端,不会启动新的进程,用exit退出,会导致容器的停止。
exec是在容器打开新的终端,并且可以启动新的进程,用exit退出,不会导致容器的停止。
推荐使用docker exec命令,因为退出容器终端,不会导致容器的停止。
一般用-d后台启动的程序,再用exec进入对应容器实例。
从容器内拷贝文件到主机上
docker cp 容器id:容器内路径 主机路径
导入和导出容器
docker export 容器id > 路径(默认当前路径)
export:导出容器的内容留作为一个tar归档文件[对应import命令]
docker import - 镜像用户名/镜像名:镜像版本号
import:从tar包中的内容创建一个新的文件系统再导入为镜像[对应export]
案例:
docker export 容器id > 文件名.tar
cat 文件名.tar|docker import - 镜像用户名/镜像名:镜像版本号
小总结
命令 | 英文说明 | 中文说明 |
---|---|---|
attach | Attach to a running container | 当前shell下attach 连接指定运行镜像 |
build | Build an image from a Dockerfile | 通过Dockerfile定制镜像 |
commit | Create a new image from a container changes | 提交当前容器为新的镜像 |
cp | Copy files/folders from the containers filesystem to the host path | 从容器中拷贝指定文件或者目录到宿主机中 |
create | Create a new container | 创建一个新的容器,同run,但不启动容器 |
diff | Inspect changes on a container’s filesystem | 查看docker容器变化 |
events | Get real time events from the server | 从docker服务获取容器实时事件 |
exec | Run a command in an existing container | 在已存在的容器上运行命令 |
export | Stream the contents of a container as a tar archive | 导出容器的内容流作为-一个 tar归档文件[对应import] |
history | Show the history of an image | 展示一个镜像形成历史 |
images | List images | 列出系统当前镜像 |
import | Create a new filesystem image from the contents of a tarball | 从tar包中的内容创建一个 新的文件系统映像[对应export] |
info | Display system-wide information | 显示系统相关信息 |
inspect | Return low-level information on a container | 查看容器详细信息 |
kill | Kill a running container | kill指定docker容器 |
load | Load an image from a tar archive | 从一个tar包中加载一个镜像[对应save] |
login | Registe or Login to the docker registry server | 注册或者登陆一个docker源服务器 |
logout | Log out from a Docker registry server | 从当前Docker registry退出 |
logs | Fetch the logs of a container | 输出当前容器日志信息 |
port | Lookup the public-facing port which is NAT-ed to PRIVATE_PORT | 查看映射端口对应的容器内部源端口 |
pause | Pause all processes within a container | 暂停容器 |
ps | List containers | 列出容器列表 |
pull | Pull an image or a repository from the docker registry server | 从docker镜像源服务器拉取指定镜像或者库镜像 |
push | Push an image or a repository to the docker registry server | 推送指定镜像或者库镜像至docker源服务器 |
restart | Restart a running container | 重启运行的容器 |
rm | Remove one or more containers | 移除一个或者多个容器 |
rmi | Remove one or more images | 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或-f强制删除] |
run | Run a command in a new container | 创建一个新的容器并运行一个命令 |
save | Save an image to a tar archive | 保存一个镜像为一个tar包[对应 load] |
search | Search for an image on the Docker Hub | 在docker hub中搜索镜像 |
start | Start a stopped containers | 启动容器 |
stop | Stop a running containers | 停止容器 |
tag | Tag an image into a repository | 给源中镜像打标签 |
top | Lookup the running processes of a container | 查看容器中运行的进程信息 |
unpause | Unpause a paused container | 取消暂停容器 |
version | Show the docker version information | 查看docker 版本号 |
wait | Block until a container stops, then print its exit code | 截取容器停止时的退出状态值 |
Docker镜像
镜像
是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。
只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。
分层的镜像
以我们的pull为例,在下载的过程中我们可以看到docker的镜像好像在一层一层的下载
UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual
filesystem)。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的
Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的LinuxUnix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system),在boots之上.包含的就是典型Linux系统中的l/dev, /proc, /bin,/etc等等标准目录和文件。roots就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
平时我们安装进虚拟机的centos都是好几个G,为什么docker这里才200m??
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootts会有差别,因此不同的发行版可以公用bootfs 。
为什么Docker镜像采用这种分层结构?
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
比如说有多个镜像都从相同的base镜像构建而来,那么Docker Host只需在磁盘上保存一份base镜像;同时内存中也只需加载一份base镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
重点理解
Docker镜像层都是只读的,容器层是可写的。
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
所有对容器的改动-无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。
Docker镜像commit操作案例
docker commit提交容器副本使之成为一个新的镜像
docker commit -m=”提交的描述信息” -a=”作者” 容器ID 要创建的目标镜像名:[标签名]
演示ubuntu容器安装vim:
从Hub上下载ubuntu镜像到本地并成功运行
docker pull ubuntu
docker run -it ubuntu /bin/bash
原始的默认ubuntu镜像是不带着vim命令的,执行vim会报错
外网连通的情况下,安装vim
在ubuntu容器中执行以下命令
1
2
3
4
5更新包管理工具
apt-get update
然后安装我们需要的vim
apt-get -y install vim安装完成后,commit我们自己的新镜像
在主机执行commit命令,注意,不是ubuntu容器中
1
2docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
docker commit -m="add vim cmd" -a="zxp" 刚才的容器ID custom/ubuntu:1.0启动我们的新镜像并和原来的对比
docker images会发现新镜像id会比原镜像大小大,因为新增了vim指令
docker run -it 新镜像id/镜像名 /bin/bash
发现新容器直接可以使用vim命令
小总结
Docker中的镜像分层,支持通过扩展现有镜像,创建新的镜像。类似Java继承于一个Base基础类,自己再按需扩展。新镜像是从base镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
本地镜像发布到阿里云
创建阿里云镜像仓库
按照命令来完成推送和拉取
创建成功后会有个操作指南,按照上边的命令来操作,如下,是我的
登录
1 | docker login --username=用户名 registry.cn-hangzhou.aliyuncs.com |
推送
1 | docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/zxp_learn/learn:[镜像版本号] |
拉取
1 | docker pull registry.cn-hangzhou.aliyuncs.com/zxp_learn/learn:[镜像版本号] |
本地镜像发布到私有库
下载镜像Docker Registry
docker pull registry
运行私有库Registry,相当于本地有个私有Docker Hub
1 | docker run -d -p5000:5000 -v /zxp/myregistry/:/tmp/registry --privileged=true registry |
-v /zxp/myregistry/:/tmp/registry –privileged=true后边会说,容器卷
默认情况,仓库被创建在容器的**/var/lib/registry**目录下,建议自行用容器卷映射,方便与宿主机联调
案例演示创建一个新镜像,ubuntu安装ifconfig命令
与Docker镜像commit操作案例一节一样,只不过命令为
1 | apt-get update |
curl验证私服库上有什么镜像
1 | curl -XGET http://宿主机IP:5000/v2/_catalog |
返回{“repositories”:[]}说明什么也没有
因为我使用的是腾讯云,如果使用公网IP访问,需要在网站控制台开放5000端口,阿里云应该也一样
将新镜像xxx修改符合私服规范的tag
按照公式:docker tag 镜像:Tag 私服Host:私服Port/可以自定义的镜像名:可以自定义的Tag好
例如:docker tag custom/ubuntu:1.1 127.0.0.1:5000/custom/ubuntu:1.1
个人理解:
私服Host:私服Port这里就相当于告诉了docker我们的私服地址
修改配置文件使之支持http
cat /etc/docker/daemon.json
1 | { |
vim命令增加:”insecure-registries”:[“宿主机IP:私服端口”],注意中间有个逗号,别漏了。
1 | { |
上述理由: docker默认不允许htp方式推送镜像,通过配置选项来取消这个限制。====>修改完后如果不生效,建议重启docker(systemctl restart docker),重启之后记得run registry镜像,我就忘了,push的时候一直提示拒绝😂
push推送到私服库
docker push 容器名:tag
例:
docker push 127.0.0.1:5000/custom/ubuntu:1.1
个人理解:发现这里不用填写私服地址,因为在将新镜像xxx修改符合私服规范的tag一节中已经按照规范告诉了docker我们要push至哪个私服
curl验证私服库上有什么镜像
1 | curl -XGET http://宿主机IP:5000/v2/_catalog |
可以看到新推送的:{“repositories”:[“custom/ubuntu”]}
pull到本地运行
docker pull 私服IP:私服端口/镜像名:镜像Tag
例如:
docker pull 127.0.0.1:5000/custom/ubuntu:1.1
docker run -it 127.0.0.1:5000/custom/ubuntu:1.1
测试ifconfig即可
O(∩_∩)O~~~
Docker容器卷
坑,–privileged=true
Docker挂载主机目录访问如果出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个–privileged=true参数即可。
如果是CentOS7安全模块会比之前系统版本加强,不安全的会先禁止,所以目录挂载的情况被默认为不安全的行为,
在SELinux里面挂载目录被禁止掉了,如果要开启,我们一般使用–privileged=true命令,扩大容器的权限解决挂载目录没有权限的问题,也即使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限。
还记得上一讲中的参数v么
docker run -d -p5000:5000 -v /zxp/myregistry/:/tmp/registry –privileged=true registry
-v /zxp/myregistry/:/tmp/registry
-v:要添加容器卷
冒号左侧(/zxp/myregistry/):宿主机的路径
冒号右侧(/tmp/registry):容器内的路径
默认情况下,仓库被创建在容器的/var/lib/registry目录下,建议自行用容器卷映射,方便与宿主机联调
是什么
一句话:有点类似我们Redis里面的rdb和aof文件
将docker容器内的数据保存进宿主机的磁盘中
运行一个带有容器卷存储功能的容器实例
docker run -it –privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
能干嘛
*将运用与运行的环境打包镜像,run后形成容器实例运行,但是我们对数据的要求希望是持久化的。
Docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然也就没有了。为了能保存数据在docker中我们使用卷。
特点:
- 数据卷可在容器之间共享或重用数据
- 卷中的更改可以直接实时生效,爽
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
数据卷案例
宿主vs容器之间映射添加容器卷
直接命令添加
命令
docker run -it –privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
例:docker run -d -p5000:5000 -v /zxp/myregistry/:/tmp/registry –privileged=true registry
查看数据卷是否挂载成功
docker inspect 容器id
查看Mounts字段
容器和宿主机之间数据共享
- docker修改,主机同步获得
- 主机修改,docker同步获得
- docker容器stop,主机修改,docker容器重启看数据是否同步
读写规则映射添加说明
读写(默认)
docker run -it –privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
例:docker run -d -p5000:5000 –privileged=true -v /zxp/myregistry/:/tmp/registry:rw registry
只读(ro)
容器实例内部被限制,只能读取不能写
docker run -it –privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
例:docker run -d -p5000:5000 –privileged=true -v /zxp/myregistry/:/tmp/registry:ro registry
ro是read only的缩写
卷的继承和共享
容器1完成和宿主机的映射
容器2继承容器1的规则
1
2
3父类可是是容器名和容器id
例:docker run -it --volumes-from 0a5dcb032464 --name=u3 ubuntu
docker run -it --privileged=true --volumes-from 父类 镜像名
实践
docker 安装 mysql
1 | docker run \ |
docker 安装 redis
推荐安装6.2.6版本
拉取redis镜像
如果拉取比较缓慢,可以使用docker镜像,不过多解释,大佬们的docker加速镜像
1 | docker pull redis:6.2.6 |
创建redis配置文件
1 | mkdir /root/redis && cd /root/redis |
1 | 注释掉,表示允许所有ip链接 |
启动redis容器
1 | docker run --privileged |
查看容器日志
1 | docker logs -f redis |
打包本地镜像并推送远程仓库
基于当前目录下的Dockerfile文件构建镜像
以镜像名为hw,版本为latest举例
1 | docker build -t 镜像名:镜像版本 . |
开始发布docker镜像
docker tag 本地镜像名:版本 远程仓库地址/镜像名:版本
1 | docker tag hw:latest hw:latest |
推送docker镜像
docker push hw:latest