提醒:本文最后更新于2023-02-13 19:03,文中所关联的信息可能已发生改变,请知悉!
Docker是什么
镜像,容器,仓库。
docker与System的关系
容器虚拟化的是操作系统而不是硬件,容器之间是共享同一套操作系统资源的。
虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统。因此容器的隔离级别会稍低一些。
LXC:
KVM:
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
获取镜像
$ docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
#docker pull --help 查看更多
#docker COMMAND --help 命令帮助
#列出本地镜像
docker images
#搜索镜像
docker search mysql
#例如docker pull badapple9/speedtest-x,拉取speedtest-x项目,用户名badapple9/软件名#speedtest-x,此处表示默认地址是 Docker #Hub(docker.io)
#仓库名若不给出,则表示官方镜像
如docker pull ubuntu:18.04
没有给出地址,默认docker hub,没有给出仓库名,实际地址docker.io/library/ubuntu:18.04
运行容器(进入)
#ubuntu18为例
docker run -it --rm ubuntu:18.04 bash
-i: 交互式操作
-t: 终端
–rm: 容器退出后删除
ubuntu: 18.04:基础镜像
bash: 交互式命令
docker run [可选参数] image
–name=”名字” 指定容器名字
-d 后台方式运行
-it 使用交互方式运行,进入容器查看内容
-p 指定容器的端口
(
-p ip:主机端口:容器端口 配置主机端口映射到容器端口
-p 主机端口:容器端口
-p 容器端口
)
-P 随机指定端口(大写的P)
列出下载镜像
需要明白镜像和容器的关系:
镜像是静态的定义,容器是镜像运行的实体,容器实际上是在镜像的上面加了一层读写层,在运行的容器里做任何改动都是写入到读写层。删除容器之后,等于删除读写层,对文件的改动也会丢失。
#列出顶层镜像
docker image ls
#列出活动容器
docker ps
#列出所有容器
docker ps -a
#更多命令
docker ps --help
docker容器大小可能会比实际镜像大小大,镜像是压缩存储在仓库中,而实际使用时需要展开。
由于 Docker 镜像是多层存储结构,并且可以继承、复用,因此不同镜像可能会因为使用相同的基础镜像,从而拥有共同的层。由于 Docker 使用 Union FS,联合文件系统是docker镜像的基础,镜像可以通过分层来继承,相同的层只需要保存一份即可,因此实际镜像硬盘占用空间很可能要比这个列表镜像大小的总和要小的多。
docker中间层
相同的层只会存一遍,而这些镜像是别的镜像的依赖,因此并不会因为它们被列出来而多存了一份,无论如何你也会需要它们。只要删除那些依赖它们的镜像后,这些依赖的中间层镜像也会被连带删除。
删除镜像
docker image rm [OPTIONS] IMAGE ID [IMAGE…](docker rmi -f 镜像id)
IMAGE ID 通常取ID前三个字符(人工删除的情况下)
[OPTIONS]可选 -f 强制移除
构建简单web容器
-d 后台运行, -p 端口映射 宿主机端口:容器端口 ,nginx 作为基础镜像,--name 自定义名字
docker run --name webserver -d -p 80:80 nginx
Docker容器与宿主机直接文件拷贝
#拷贝容器的文件到主机中
docker cp 容器id:容器内路径 目的主机路径
#拷贝宿主机的文件到容器中
docker cp 目的主机路径 容器id:容器内路径
docker cp containerid:/opt/testnew/file.txt /opt/test/
docekr cp /opt/test containerid:/opt/testnew/file.txt
#容器是否启动均会拷贝,且相同文件会替代
进入容器
#进入容器,修改存储层
docker exec -it webserver bash
#例如修改默认的index.html
MySQL的部署
下载并运行
#拉取并运行容器
docker run -d --name mysql-5.7 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
#参数说明:
-p 3306:3306 :映射容器服务的 3306 端口到宿主机的 3306 端口,外部主机可以直接通过 宿主机ip:3306 访问到 MySQL 的服务。
MYSQL_ROOT_PASSWORD=123456:设置 MySQL 服务 默认账号root 用户的密码。
进入容器查看mysql服务 进入容器,并通过账号root查看MySQL服务能否正常连接
docker exec -it 9b3aad6819ff /bin/bashell
mysql -h localhost -u root -p
镜像构成/容器打包成镜像
镜像是多层存储,每一层是在前一层的基础上进行的修改;而容器同样也是多层存储,是在以镜像为基础层,在其基础上加一层作为容器运行时的存储层。利用nginx作为基础容器,构建webserver
运行一个容器,并对容器内容做修改,而不使用挂载文件夹(卷),对其内部任何的修改都将保存在存储层,如果想将修改之后的容器保存成镜像,方便在其他设备使用,docker中提供docker commit 命令
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]
#举例 \换行符 webserver 容器名 仓库nginx 标签 v2
docker commit \
--author "MAOBUNI <[email protected]>" \
--message "alter default index html" \
webserver \
nginx:v2
使用docker commit 意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为 黑箱镜像,除了制作镜像的人知道执行过什么命令、怎么生成的镜像,别人根本无从得知。而且,即使是这个制作镜像的人,过一段时间后也无法记清具体的操作。黑箱镜像难以维护,并且docker的是分层存储,修改仅仅影响当前层,层层累计,镜像臃肿。考虑使用Dockerfile 构建镜像。
Dockerfile
Dockerfile是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。 Docker通过读取Dockerfile中的指令自动生成映像。包括基础镜像,镜像操作,镜像启动执行命令
#创建文件Dockerfile
touch Dockerfile
#编辑
vim Dockerfile
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
#Dockerfile所在目录执行
#docker build [OPTIONS] PATH | URL | -
#RUN命令会构建一个容器来执行命令,随后得到一个新的镜像并删除原执行容器
docker bulid -t nginx:v1 .
FROM:
指定基础镜像(FROM scratch 空白镜像,不以任何镜像为基础镜像,服务类镜像nginx, redis等,语言类镜像python,golang等,基础操作系统镜像centos,alpine等)
RUN:
shell格式的run:RUN [命令](例如 RUN echo ‘hello’ >> /usr/share/nginx/html/index.html)
exec格式:RUN [“可执行文件”, “参数1”, “参数2”]
Docker每个RUN指令都会构建一层,将复杂的shell脚本表现为多个RUN命令,导致镜像臃肿 ,且容易出错。(Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层。)
例:以debian为基础镜像,安装redis,构建新的镜像,多个RUN命令
FROM debian:stretch
RUN apt-get update
RUN apt-get install -y gcc libc6-dev make wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install
Dockerfile正确写法
FROM debian:stretch
RUN set -x; buildDeps='gcc libc6-dev make wget' \
&& apt-get update \
&& apt-get install -y $buildDeps \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& mkdir -p /usr/src/redis \
&& tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
&& make -C /usr/src/redis \
&& make -C /usr/src/redis install \
&& rm -rf /var/lib/apt/lists/* \
&& rm redis.tar.gz \
&& rm -r /usr/src/redis \
&& apt-get purge -y --auto-remove $buildDeps
撰写 Dockerfile 的时候,要经常提醒自己,这并不是在写 Shell 脚本,而是在定义每一层该如何构建。(Dockerfile文件名仅是默认习惯,且位置默认放在上下文目录中)
其他构建镜像方法
docker build 其他用法
git repo构建
docker build -t name:tag URL
tar压缩包构建
docker build http://server/context.tar.gz
Docker 引擎会下载这个包,并自动解压缩,以其作为上下文,开始构建。
标准输入读取Dockerfile构建
docker build - < Dockerfile
(cat Dockerfile | docker build -
)
没有上下文,因此不可以像其他方法那样可以将本地文件 COPY
进镜像之类的事情。
Dockerfile指令详解
。。。
操作容器
当利用 docker run
来创建容器时,Docker 在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从 registry 下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
- 再次启动命令 docker container start
查看容器中运行的进程
进入容器之后,可以使用ps或top命令,即可以观察到docker的轻便。
守护态/后台运行:docekr run -d
查看容器日志:docker container logs [container ID or NAMES]
终止容器:docker container stop
重启一个容器:docker container restart
进入容器
docker attach 和 docker exec 命令
exec命令
docker exec 后常 用 -i 和-t 命令,前台运行
-i并没分配伪终端,操作结果返回在宿主机
#例子
docker exec -it container ID bash
ls
index.html result.html ...
#退出不会导致容器停止运行
exit
attach命令
docker run -itd -p 9001:80 badapple9/speedtest-x
#attach
docekr attach container ID
#进入容器执行命令
#退出 会导致容器停止运行
exit
容器快照导出/导入
docker export container ID > filename.tar
cat filename.tar | docker import - test/ubuntu:v1.0
(容器快照体积更小,仅记录容器状态,丢弃原始标签等数据)
删除容器
删除处于停止状态的容器:docker container rm name
清理所有处于停止状态的容器:docker container prune