学习笔记源自于:https://yeasy.gitbook.io/docker_practice/image/list
什么是 Docker
Docker 是利用 go 写的轻量化容器,Docker 通过 cgroup 等命令来实现进程级别的隔离,与虚拟机相比容器启动速度更快更加灵活不过隔离效果远远不如 VM
镜像
在使用 Docker 的时候我们只需要运行 Docker run 就能快速启动容器来进行应用
镜像主要是提供 Docker 中运行应用所必须的依赖
分层存储
镜像因为有的时候都是操作系统,所以如果不进行分层存储的话就会造成过多镜像的堆积在本地越来越大,所以为了减少镜像占用的体积,采取了分层存储的概念。也就是说如果该镜像中的一些基础或者底层是原来就有的那么就不会下载一个已有的镜像了
容器
镜像与容器的关系就相当于在 Java 中的类和实例,类就是静态,实例就是运行中的实例是动态的
所以与之相对的 镜像就是静态的,容器是镜像运行时的实体。创建之后的容器可以创建、暂停、终止。
容器实质就是进程,只不过通过一些配置拥有自己的根目录、自己的网络配置、自己的资源 。
镜像使用是分层的,所以镜像就是基础层,容器在镜像的基础上进行运行,所以运行之后的数据都是存储在存储层,但是存储层会随着容器消失而消失 ,所以 Docker 建议我们运行中的数据都要存储在数据卷中或者是与宿主机相绑定的目录上
数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失
仓库
那么创建好的镜像,总不能放到自己本地把 ,所以就需要有个地方来进行存放 因此 Docker Register 就诞生了
一个 Docker Registry 中可以包含多个 仓库(Repository
);每个仓库可以包含多个 标签(Tag
);每个标签对应一个镜像。
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签>
的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest
作为默认标签。
以 Ubuntu 镜像 为例,ubuntu
是仓库的名字,其内包含有不同的版本标签,如,16.04
, 18.04
。我们可以通过 ubuntu:16.04
,或者 ubuntu:18.04
来具体指定所需哪个版本的镜像。如果忽略了标签,比如 ubuntu
,那将视为 ubuntu:latest
。
仓库名经常以 两段式路径 形式出现,比如 jwilder/nginx-proxy
,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。
镜像
使用镜像
由于镜像只是静态使用,所以我们需要来创建容器
docker run -it --rm ubuntu:18.04 bash
-it: -i 代表交互式操作,t代表终端 这里代表终端是 bash
--rm: 容器退出之后就会进行删除
列出镜像
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest 5f515359c7f8 5 days ago 183 MB
nginx latest 05a60462f8ba 5 days ago 181 MB
mongo 3.2 fe9198c04d62 5 days ago 342 MB
<none> <none> 00285df0df87 5 days ago 342 MB
ubuntu 18.04 329ed837d508 3 days ago 63.3MB
ubuntu bionic 329ed837d508 3 days ago 63.3MB
镜像体积
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 24 0 1.992GB 1.992GB (100%)
Containers 1 0 62.82MB 62.82MB (100%)
Local Volumes 9 0 652.2MB 652.2MB (100%)
Build Cache 0B 0B
虚悬镜像
$ docker image prune
中间层镜像
由于 docker 镜像都是多层结构,但是一般使用 docker image ls
中所显示的都是顶层的镜像,只有利用 docker image ls -a
才会显示出所有的镜像
同时可以通过过滤来查看一些特定时间轴的,向下面这个可以显示出自动 mongo 之后下载建立的镜像
docker image ls -f since=mongo:3.2
删除镜像
docker image rm xxxx
[慎用] 利用 commit 将容器做成镜像
将容器保存成镜像
通过 docker diff 命令查看前后改动的地方
docker diff NAMES
docker commit 命令可以将容器中的存储层拉下来保存到镜像中
要知道,当我们运行一个容器的时候(如果不使用卷的话),我们做的任何文件修改都会被记录于容器存储层里。而 Docker 提供了一个
docker commit
命令,可以将容器的存储层保存下来成为镜像。换句话说,就是在原有镜像的基础上,再叠加上容器的存储层,并构成新的镜像。以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化
docker commit 语法
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]
例:
docker commit --author "KpLi0rn" --message "修改了默认网页" webserver nginx:v2
通过 Docker history 来查看历史改动
来运行之前保存好的镜像
docker run --name "MyServer" -d -p 8891:80 nginx:v2
这种方式虽然做起来非常的方便但是会造成我们打包的镜像会加进来很多臃肿的依赖,除了我们自己别人都不知道这个镜像中到底是哪些命令,可以看到我们执行了操作之后这里的 CREATED BY 并不是确切的命令,所以是未知的,同时这里我们只是修改了一个 index.html 但是可以看出来我们这里的 SIZE 变化也是比较大的
所以我们在打包镜像的时候需要利用 Dockerfile 来进行打包
利用 Dockerfile 来定制镜像
Docker 提供了很多基础类库,可以直接通过 FROM 来拖取基础镜像
然后利用 RUN 命令来进行命令的执行
FROM nginx
RUN echo '<h1>This is My First DockerFile</h1>' > /usr/share/nginx/html/index.html
ps:空白镜像 scratch 有的时候可以不以任何系统为基础,所以我们的指令就会作为镜像的第一层,这样有一个好处就是可以减少镜像的体积
创建镜像,在当前 dockerfile 的位置来进行镜像的创建
docker build -t nginx:v3 .
还有一个需要介绍的就是, RUN 作为 dockerfile 中最常用的命令在使用的时候是需要注意的
在 dockerfile 中每一条命令就是一层 所以下面这个安装 redis 的过程就需要 7 层,但是这样的话会导致镜像变的非常的臃肿,因为对于用户来说 redis 安装只需要一层就好了
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
所以我们只需要利用 && 就可以了
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
镜像构建上下文
回看上面的命令
docker build -t nginx:v3 .
之前我一直以为 . 是当前的 dockerfile 地址,其实不是的在docker中这个打包其实是在服务端的 docker 引擎中进行打包的 ,这里的 . 其实就是相对路径,docker 在执行build 的命令的时候会把当前的内容都打包传到远程的 server 上(利用 rest api 来进行)所以传上去了之后 . 就相当于是相对路径 ,如果遇到 copy 等命令的时候就能将资源进行正确的添加
所以我们在执行一些 copy 命令的时候需要利用相对路径,或者就是根据我们的上下文路径来进行添加
理解构建上下文对于镜像构建是很重要的,避免犯一些不应该的错误。比如有些初学者在发现 COPY /opt/xxxx /app
不工作后,于是干脆将 Dockerfile
放到了硬盘根目录去构建,结果发现 docker build
执行后,在发送一个几十 GB 的东西,极为缓慢而且很容易构建失败。那是因为这种做法是在让 docker build
打包整个硬盘,这显然是使用错误。
一般来说,应该会将 Dockerfile
置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 .gitignore
一样的语法写一个 .dockerignore
,该文件是用于剔除不需要作为上下文传递给 Docker 引擎的。
那么为什么会有人误以为 .
是指定 Dockerfile
所在目录呢?这是因为在默认情况下,如果不额外指定 Dockerfile
的话,会将上下文目录下的名为 Dockerfile
的文件作为 Dockerfile。
这只是默认行为,实际上 Dockerfile
的文件名并不要求必须为 Dockerfile
,而且并不要求必须位于上下文目录中,比如可以用 -f ../Dockerfile.php
参数指定某个文件作为 Dockerfile
。
当然,一般大家习惯性的会使用默认的文件名 Dockerfile
,以及会将其置于镜像构建上下文目录中。
还可以利用远程 git 来进行创建
```dockerfile
$ docker build -t hello-world https://github.com/docker-library/hello-world.git
Step 1/3 : FROM scratch
--->
Step 2/3 : COPY hello /
---> ac779757d46e
Step 3/3 : CMD ["/hello"]
---> Running in d2a513a760ed
Removing intermediate container d2a513a760ed
---> 038ad4142d2b
Successfully built 038ad4142d2b
### 操作容器
docker 查看容器全部命令,不进行省略
docker ps -a --no-trunc
![image-20211215215445654](https://cdn.wjlshare.com/image-20211215215445654.png)
#### 守护态运行
-d:就是 Docker 容器在后台运行
举个例子:docker run -d --name yarn -p 8042:8042 -p 8032:8032 kpli0rn/hadoop-rpc-vuln:3.3.0
可通过 docker container logs [container ID] 来查看控制台的日志情况
#### 进入容器内部
docker exec -it 69d137adef /bin/bash
#### 容器导入&导出
https://segmentfault.com/a/1190000040340427 导入导出的文章
##### 导出
docker export [container id] > demo.tar
![image-20211215213847156](https://cdn.wjlshare.com/image-20211215213847156.png)
导出来的就是一个基本的 linux 小目录
![image-20211215213936295](https://cdn.wjlshare.com/image-20211215213936295.png)
##### 导入
cat /Users/kpli0rn/Desktop/fastjson.tar | docker import - test/fastjson:v1.0
其实直接 import 就行了 docker import fastjson.tar
![image-20211215214139310](https://cdn.wjlshare.com/image-20211215214139310.png)
导入之后变成了 docker iamge
![image-20211215214245110](https://cdn.wjlshare.com/image-20211215214245110.png)
想要运行镜像必须要在运行的最后加上 command
```dockerfile
docker run -d -p 8090:8090 test/fastjson java -Dserver.address=0.0.0.0 -Dserver.port=8090 -jar /usr/src/fastjsondemo.jar
这样就运行成功了
清除
删掉所有终止的容器
docker container prune
访问仓库
把镜像上传到 dockerhub 上的时候
// 先用 docker tag 打个 tag
docker tag ubuntu:18.04 username/ubuntu:18.04
// 然后再push上去
docker push username/ubuntu:18.04
未完待续.....