Cover photo

Docker学习与使用

Docker—学习与应用

1.Docker概述

Docker是一种轻量级的容器化技术,可以将应用和其依赖项封装成一个可移植的容器,这使得在不同的环境中部署和运行应用程序变得更加容易。Docker容器技术的核心思想是隔离和打包装箱,每个容器是互相隔离的。

Docker诞生于2010年,最初是由一家名为dotCloud的公司开发的,该公司提供了一些pass的云计算服务。Docker最初并没有受到行业的关注,直到2013年它成为了开源项目,越来越多的人开始认识到它的优点,Docker也因此变得越来越流行。

docker-logo
docker-logo

与传统的虚拟机技术相比,Docker的优点在于轻量级、资源占用少、启动快速等方面。Docker容器化技术也是一种虚拟化技术,但与虚拟机不同的是,容器内的应用直接运行在宿主机的内核上,没有自己的内核和虚拟硬件,每个容器是互相隔离的,因此可以更快速地部署和运行应用程序。

docker-structure
docker-structure

Docker的作用在于实现DevOps,即开发和运维的快速协作,将应用程序的构建、测试、部署等过程自动化,提高效率和质量,降低成本。Docker提供了一整套的工具和服务,包括Docker引擎、Docker Hub、Docker Compose等,可以方便地管理和维护容器化应用程序。

Docker是基于Golang开发的开源项目

官网地址:https://www.docker.com/

文档地址:https://docs.docker.com/

仓库地址:https://hub.docker.com


2.Docker安装

2.1 Docker的基本组成

docker
docker

Docker是一种轻量级容器技术,它的核心组成部分有镜像、容器和仓库。本文将在下面介绍这三个组成部分的概念和作用。

  • 镜像:镜像就像是一个模板,可以通过它来创建容器服务。例如,使用tomcat镜像可以创建一个tomcat01容器,容器中可以运行最终服务或项目。

  • 容器:容器则是通过镜像来创建的,利用容器技术独立运行一个或多个应用程序。启动、停止、删除等基本命令可以操作容器。可以把容器理解为一个简易的Linux系统。

  • 仓库:仓库是存放镜像的地方,分为公有仓库和私有仓库。DockerHub和阿里云都有容器服务器,可以配置镜像加速。

通过使用Docker,可以方便地创建、部署和管理应用程序,加速开发和部署流程,提高开发效率和应用程序的可移植性。

2.2 搭建Linux环境

本文,笔者使用的是Unbuntu18.04版本的虚拟机,使用XShell连接工具对虚拟机进行操作,配置完成Linux环境后确保Xshell可以正常访问Ubuntu文件。

ubuntu
ubuntu

2.3 安装Docker

  1. 首先需要先卸载掉Docker的旧版本文件数据。

    sudo apt-get remove docker docker-engine docker.io containerd runc
    
  2. 通过仓库的方式安装。

     sudo apt-get update
    
     sudo apt-get install \
        ca-certificates \
        curl \
        gnupg \
        lsb-release
    
  3. 下面添加Docker的官方GPG key。

     curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
    
     # 国内阿里云版
     curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | apt-key add -
    
  4. 接下来验证key的指纹

    sudo apt-key fingerprint 0EBFCD88
    

    正常的输出为:

    root@camile:/# sudo apt-key fingerprint 0EBFCD88
    pub   rsa4096 2017-02-22 [SCEA]
          9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
    uid           [ 未知 ] Docker Release (CE deb) <docker@docker.com>
    sub   rsa4096 2017-02-22 [S]
    
  5. 下面我们添加稳定版的docker仓库或者国内阿里云版本。

    # 官方版本
    sudo add-apt-repository \
       "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
       $(lsb_release -cs) \
       stable"
    # 国内阿里云版
    sudo add-apt-repository \
       "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
       $(lsb_release -cs) \
       stable"
    
  6. 安装我们最新版本的docker ce和container。

     sudo apt-get update
     sudo apt-get install docker-ce docker-ce-cli containerd.io
    
  7. 查看我们安装的docker版本信息。

    docker --version
    
  8. 将非root用户加入docker组,以允许免sudo执行docker.

    sudo gpasswd -a 用户名 docker
    

    重启服务并刷新docker组成员:

    sudo service docker restart
    newgrp - docker
    

    设置开机自启动并启动 Docker-ce(安装成功后默认已设置并启动,可忽略)

    sudo systemctl enable docker
    sudo systemctl start docker
    
  9. 接下来我们安装docker-compose https://www.runoob.com/docker/docker-compose.html

    sudo curl -L https://github.com/docker/compose/releases/download/1.25.4/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
    
    sudo chmod +x /usr/local/bin/docker-compose
    
    sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
    
    docker-compose --version
    
  10. 测试我们的第一个镜像hello-world。

    docker run hello-world
    
hello-world
hello-world
  1. 卸载docker命令如下所示:

     sudo apt-get purge docker-ce docker-ce-cli containerd.io
     sudo rm -rf /var/lib/docker
     sudo rm -rf /var/lib/containerd
    

2.4 配置阿里云镜像加速器

在阿里云上,提供了一些免费的容器镜像服务,我们找到控制台->左侧菜单->容器镜像服务->镜像加速器,其中Ubuntu配置镜像加速器的命令已给出:

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://alvnh3pv.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

2.5 回顾

上面我们运行了一个docker run的命令,笔者绘制了一个流程图供大家参考

process
process

那么Docker究竟是怎么工作的呢?这里笔者简单的介绍一下,Dcoker是一个 Client-Server结构的系统,Docker的守护进程运行在主机上,通过Socker从客户端访问。而DockerServer 接收到 Docker-Client 的指令,就会执行这个命令。如下所示

工作方式
工作方式

3.Docker常用命令

这一节,笔者总结了一些Docker的常用命令,速览以下有助于后续的使用。对于一些命令,笔者会在虚拟机上试验并给出响应结果。

3.1 帮助命令

docker version        # 版本信息
docker info           # 显示docker的系统信息,包括容器和镜像的信息
docker [命令] --help   # 帮助文档,官网在 doc下的reference 下的 command-line reference

3.2 镜像命令

docker images:查看本机所有的镜像

root@camile:~# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    feb5d9fea6a5   5 months ago   13.3kB

# 解释
REPOSITORY:镜像的仓库源
TAG:镜像的标签
IMAGE ID:镜像的ID
CREATED:镜像的创建时间
SIZE:镜像的大小

# 可选项
Options:
  -a, --all             # 列出所有镜像 
  -f, --filter          # 过滤镜像
  -q, --quiet           # 只显示镜像的id
  -aq                   # 列出所有镜像id

**docker search:**搜索镜像

root@camile:~# docker search mysql
NAME                             DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql/mysql-server               Optimized MySQL Server Docker images. Create…   907                  [OK]

# 可选项
Options:
  -f=STARS=3000 --filter=STARS=3000

docker pull:下载镜像

# 下载镜像 docker pull 镜像名[:tag]
root@camile:~# docker pull mysql
Using default tag: latest # 默认是最新版本
latest: Pulling from library/mysql
72a69066d2fe: Pull complete  # 分层下载,docker image 的核心 联合文件系统
93619dbc5b36: Pull complete 
99da31dd6142: Pull complete 
626033c43d70: Pull complete 
37d5d7efb64e: Pull complete 
ac563158d721: Pull complete 
d2ba16033dad: Pull complete 
688ba7d5c01a: Pull complete 
00e060b6d11d: Pull complete 
1c04857f594f: Pull complete 
4d7cfa90e6ea: Pull complete 
e0431212d27d: Pull complete 
Digest: sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709  #签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 真实地址

# 等价于以下命令
docker pull docker.io/library/mysql:latest

# 指定版本下载
root@camile:~# docker pull mysql:5.7
5.7: Pulling from library/mysql
72a69066d2fe: Already exists 
93619dbc5b36: Already exists 
99da31dd6142: Already exists 
626033c43d70: Already exists 
37d5d7efb64e: Already exists 
ac563158d721: Already exists 
d2ba16033dad: Already exists 
0ceb82207cd7: Pull complete 
37f2405cae96: Pull complete 
e2482e017e53: Pull complete 
70deed891d42: Pull complete 
Digest: sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
images
images

docker rmi:删除镜像

# 按照id删除镜像
docker rmi -f 容器id # 删除指定的镜像
docker rmi -f 容器id 容器id 容器id # 删除多个镜像
docker rmi -f $(docker images -aq) # 删除全部镜像

3.3 容器命令

有了镜像,我们才可以创建容器,我们下载一个centos镜像来测试学习。

新建容器并启动

docker run [可选参数] image

# 参数说明
--name=“Name”     容器名字 tomcat01 tomcat02 用来区分容器
-d                后台方式运行
-i -t -it         使用交互方式运行,进入容器查看内容
-p                指定容器的端口 -p 80808080
-p ip:主机端口:容器端口
-p 主机端口:容器端口(常用)
-p 容器端口
容器端口
-p    随机指定端口

# 测试
root@camile:~# docker run -it centos /bin/bash # 启动容器并进入容器内部
[root@f2e7722031c0 /] # 进入容器内部 root@后面就是容器的id
[root@f2e7722031c0 /]# ls # 查看容器内的centos目录
bin  etc   lib      lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr
[root@f2e7722031c0 /]# exit  # 从容器中退回主机
exit
root@camile:~# 

列出所有运行中的容器

# docker ps 命令
    # 列出当前正在运行的容器
-a    # 列出当前正在进行的容器+带出历史运行的容器
-n=?    # 显示最近几个创建的容器
-q  # 只显示容器的ID
root@camile:~# docker ps -a
CONTAINER ID   IMAGE     COMMAND       CREATED       STATUS                   PORTS     NAMES
f2e7722031c0   centos    "/bin/bash"   4 hours ago   Exited (0) 4 hours ago             amazing_rosalind

退出容器

 exit # 直接容器停止并退出
 CTRL + P + Q # 容器不停止并tui'chu

删除容器

docker rm 容器id                 # 删除指定的容器,不能删除正在运行的容器
docker rm -f $(docker ps -aq)   # 删除所有的容器
docker ps -aq | xargs docker rm # 删除所有的容器

启动和停止容器的操作

docker start 容器 id
docker restart 容器id
docker stop 容器id
docker kill 容器id

3.4 其他命令

后台启动容器

# 命令 docker run -d 镜像名;
root@camile:~# docker run -d centos
# 问题 docker ps 发现,centos 停止了

# 常见的坑, docker 容器使用后台运行,就必须有一个前台进程,docker容器发现没有应用,就会自动停止
# 容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了

查看日志

docker logs -f -t --tail 容器,没有日志

# 自己编写一段shell脚本
docker run -d centos /bin/bash -c "while true;do echo qiaowei;sleep 1;done"

# 显示日志
root@camile:~# docker logs -tf --tail 10 397eabe2c023
2022-02-26T09:21:25.266776907Z qiaowei
2022-02-26T09:21:26.268727710Z qiaowei
2022-02-26T09:21:27.270738576Z qiaowei

-tf # 显示日志
--tail  # 显示日志条数

查看容器中的进程信息

# 命令docker top 容器id
root@camile:~# docker top 19334600a733
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                14960               14931               0                   17:27               pts/0               00:00:00            /bin/bash

查看镜像的元数据

# 命令
docker inspect 容器id

进入当前正在运行的容器

# 我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置

# 命令
docker exec -it 容器id 路径

# 测试
root@camile:~# docker exec -it 19334600a733 /bin/bash
[root@19334600a733 /]# ls
bin  etc   lib      lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr
[root@19334600a733 /]# ps -ef
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 09:27 pts/0    00:00:00 /bin/bash
root         15      0  0 09:46 pts/1    00:00:00 /bin/bash
root         31     15  0 09:46 pts/1    00:00:00 ps -ef

# 方式二
docker attach 容器id
root@camile:~# docker attach 19334600a733          
[root@19334600a733 /]# ls
bin  etc   lib      lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr

# docker exec     # 进入容器后开启一个新的终端,可以在里面操作(常用)
# docker attach   # 进入容器正在执行的终端,不会启动新的进程

从容器内拷贝文件到主机上

docker cp 容器id:容器内路径 目前的主机路径

# 测试
[root@19334600a733 /]# cd /home
[root@19334600a733 home]# ls
[root@19334600a733 home]# touch test.java
[root@19334600a733 home]# exit
exit
root@camile:~# docker ps 
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
root@camile:~# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                        PORTS     NAMES
19334600a733   centos    "/bin/bash"              32 minutes ago   Exited (0) 12 seconds ago               admiring_bohr
397eabe2c023   centos    "/bin/bash -c 'while…"   39 minutes ago   Exited (137) 37 minutes ago             focused_ellis
cd940d7abbb2   centos    "/bin/bash -C 'while…"   40 minutes ago   Exited (127) 40 minutes ago             ecstatic_galileo
23db6f7950f8   centos    "/bin/bash -C 'while…"   40 minutes ago   Exited (127) 40 minutes ago             keen_sanderson
8f9ce6c66f30   centos    "/bin/bash"              43 minutes ago   Exited (0) 40 minutes ago               flamboyant_moser
root@camile:~# docker cp 19334600a733:/home/test.java /home
root@camile:~# cd home
-bash: cd: home: No such file or directory
root@camile:~# cd /home
root@camile:/home# ls
camile  test.java

# 拷贝是一个手动过程,未来我们使用 -v 卷的技术,可以实现

4.Docker部署简单环境

接下来,笔者将带领大家安装Nginx和Tomcat这两个常见的镜像。

4.1 安装Nginx

# 1.搜索镜像 search 建议大家去docker搜索,可以看到帮助文档

# 2.下载nginx镜像
docker pull nginx

# 3.运行测试
root@camile:/# docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
nginx        latest    605c77e624dd   8 weeks ago    141MB
centos       latest    5d0da3dc9764   5 months ago   231MB

# -d 后台运行
# --name 给容器命名
# -p 宿主机端口:容器内端口
root@camile:/# docker run -d --name nginx01 -p 3344:80 nginx
586cda0f86a49f103522efcf0300a8592639ae2da23c8317745a487d8373a555
root@camile:/# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                                   NAMES
586cda0f86a4   nginx     "/docker-entrypoint.…"   4 seconds ago   Up 4 seconds   0.0.0.0:3344->80/tcp, :::3344->80/tcp   nginx01
root@camile:/# curl localhost:3344
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

4.2 部署Tomcat

# 官方的使用
docker run -it --rm tomcat:9.0

# 我们之前的启动都是后台,停止了容器之后,容器还是可以查到,官方的方法一般是用完及删

# 我们的逻辑是先下载再启动
docker pull tomcat:9.0

# 启动运行
root@camile:/# docker run -d -p 3355:8080 --name tomcat01 tomcat

# 发现问腿:1.Linux命令少了 2.没有webapps,阿里云镜像的原因,默认是最小的镜像,所有不必要的都删除吊
# 保证最小的运行环境

4.3 部署ES+kibana

# es 暴露的端口很多!
# es 十分的耗内存
# es 的数据一般需要放置在安全目录!挂载
# --net somenetwork ? 网络配置

# 启动 elasticsearch
docker run -d --name elasticsearch --net somenetwork -p 9200:9200  -e "discovery.type=single-node" elasticsearch:7.6.2

# 启动了 linux就卡住了 docker stats 查看 cpu状态

# es 是十分耗内存的  1核2G

# 查看 docker stats

# 测试以下 es 是否成功了

# 赶紧关闭,增加内存的限制 -e环境配置修改
docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:tag
docker run -d --name elasticsearch --net somenetwork -p 9200:9200  -e ES_JAVA_OPTS="-Xms64m -Xmx12m" elasticsearch:7.6.2

4.4 Docker可视化工具

这里我们可以使用一个portainer,它是一个Docker的图形化界面管理工具,提供一个后台面板供我们操作,登陆进入可以管理我们的容器。

docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true   portainer/portaioner

在虚拟机中可以使用:localhost:8080来访问界面

portainer
portainer

5.Docker镜像理解

5.1 镜像是什么

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。

如何获得镜像:

  • 从远程仓库下载

  • 朋友拷贝

  • 自己制作一个镜像DockerFile

5.2 镜像加载原理

UnionFS(联合文件系统)

我们下载的时候看到的一层一层的数据就是这个。

UnionFS(联合文件系统):Union文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层地叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

特性:一次同时加载多个文件系统,但从外表看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有的底层的文件和目录。

Docker镜像加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。

bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。

rootfs (root file system),在bootfs之上。包含的就是典型Linux系统中的/dev,/proc, /bin, /etc等标准目录和文件。各种不同的操作系统发行版,比如Ubuntu , Centos等等

镜像分层
镜像分层

平时我们安装虚拟机的CentOS都是好几个G,为什么Docker这里才200M?

对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。因此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。

5.3 分层理解

分层的镜像

我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层地在下载。

下载时分层
下载时分层

思考:为什么Docker镜像要采用这种分层结构?

最大的好处,我觉得莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。

查看镜像分层的方式可以通过docker image inspect命令!

[root@iZwz99sm8v95sckz8bd2c4Z ~]# docker image inspect nginx:latest
[
    {
        "Id": "sha256:ae2feff98a0cc5095d97c6c283dcd33090770c76d63877caa99aefbbe4343bdd",
        "RepoTags": [
            "nginx:latest"
        ],
        "RepoDigests": [
            "nginx@sha256:4cf620a5c81390ee209398ecc18e5fb9dd0f5155cd82adcbae532fec94006fb9"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2020-12-15T20:21:00.007674532Z",
        "Container": "4cc5da85f27ca0d200407f0593422676a3bab482227daee044d797d1798c96c9",
        "ContainerConfig": {
            "Hostname": "4cc5da85f27c",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.19.6",
                "NJS_VERSION=0.5.0",
                "PKG_RELEASE=1~buster"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"nginx\" \"-g\" \"daemon off;\"]"
            ],
            "Image": "sha256:13bffe371b56f4aeed88218ec17d0c6f653a83b49bd3e211fc8cfa2ca5d7a3d3",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
            },
            "StopSignal": "SIGQUIT"
        },
        "DockerVersion": "19.03.12",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.19.6",
                "NJS_VERSION=0.5.0",
                "PKG_RELEASE=1~buster"
            ],
            "Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],
            "Image": "sha256:13bffe371b56f4aeed88218ec17d0c6f653a83b49bd3e211fc8cfa2ca5d7a3d3",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
            },
            "StopSignal": "SIGQUIT"
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 132935043,
        "VirtualSize": 132935043,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/cb791e78a08db7091bf2ce1d78603f1758f52199e57f1805156fe30e39067aae/diff:/var/lib/docker/overlay2/1e73a72b25af68ee9abf4eb443f778d31226e12e9af428fcc14c7b044c83b258/diff:/var/lib/docker/overlay2/88c9c01762f2af8327db65d0b0d4a64785e87c9c2ab76c62e7d03619db03a985/diff:/var/lib/docker/overlay2/7304ab112ac4a9cb91fc6f74730be28fecbe19f042e92d321aa9181424cc4b2e/diff",
                "MergedDir": "/var/lib/docker/overlay2/48b288740bbb2b07b41ed43a4d17a005c46b08d3357d2960b5ef7db4b2de6618/merged",
                "UpperDir": "/var/lib/docker/overlay2/48b288740bbb2b07b41ed43a4d17a005c46b08d3357d2960b5ef7db4b2de6618/diff",
                "WorkDir": "/var/lib/docker/overlay2/48b288740bbb2b07b41ed43a4d17a005c46b08d3357d2960b5ef7db4b2de6618/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:87c8a1d8f54f3aa4e05569e8919397b65056aa71cdf48b7f061432c98475eee9",
                "sha256:5c4e5adc71a82a96f02632433de31c998c5a9e2fccdcbaee780ae83158fac4fa",
                "sha256:7d2b207c26790f693ab1942bbe26af8e2b6a14248969e542416155a912fec30d",
                "sha256:2c7498eef94aef8c40d106f3e42f7da62b3eee8fd36012bf7379becc4cd639a2",
                "sha256:4eaf0ea085df254fd5d2beba4e2c11db70a620dfa411a8ad44149e26428caee4"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

这里指示了分层信息:

"RootFS": {
    "Type": "layers",
    "Layers": [
        "sha256:87c8a1d8f54f3aa4e05569e8919397b65056aa71cdf48b7f061432c98475eee9",
        "sha256:5c4e5adc71a82a96f02632433de31c998c5a9e2fccdcbaee780ae83158fac4fa",
        "sha256:7d2b207c26790f693ab1942bbe26af8e2b6a14248969e542416155a912fec30d",
        "sha256:2c7498eef94aef8c40d106f3e42f7da62b3eee8fd36012bf7379becc4cd639a2",
        "sha256:4eaf0ea085df254fd5d2beba4e2c11db70a620dfa411a8ad44149e26428caee4"
    ]
},

所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。

举一个简单的例子,假如基于Ubuntu Linux 16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。

该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。

3个镜像层
3个镜像层

在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个层包含3个文件,而镜像包含了来自两个镜像层的6个文件。

6个文件
6个文件

这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。

Linux上可用的存储引擎有AUFS、Overlay2、Device Mapper、Btrfs以及ZFS。顾名思义,每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。

Docker在Windows 上仅支持windowsfilter一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW[1].下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。

post image

特点

Docker镜像都是只读地,当容器启动时,一个新的可写层被加载到镜像的顶部!

这一层就是我们通常说的容器层,容器之下的都是镜像层!

5.4 commit镜像

当我们想要保存当前容器的状态,就可以通过commit来提交,获得一个镜像:

docker commit 提交容器成为一个新的副本

docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[tag]

实战测试

# 启动一个默认的tomcat

# 发现这个默认的 tomcat 没有webapps应用,镜像的原因,官方的镜像默认 webapps 下是没有文件的

# 自己拷贝进去基本的文件

# 将我们操作过的容器通过commit提交为一个镜像!我们以后就可以使用我们修改过的镜像即可,这也就是我们自己的一个修改镜像。

6.Docker容器数据卷

6.1 什么是容器数据卷

容器数据卷是Docker中一种用于持久化数据的技术,它可以让容器中的数据在容器删除后不会丢失。Docker的理念是将应用和环境打包成一个镜像,但如果数据都在容器中,那么容器删除后数据也会消失。因此,需要使用数据卷技术实现数据持久化和同步操作。

挂载
挂载

例如,在使用MySQL时,如果容器删除,则数据库中的数据也会丢失,因此需要将MySQL数据存储在本地并使用卷技术实现容器和本地数据的同步。卷技术通过目录挂载实现,将容器内的目录挂载到Linux系统上。因此,容器间也可以共享数据,实现数据共享。容器数据卷是Docker中非常重要的一部分,可以实现容器的持久化和同步操作,为容器应用提供了强大的数据管理功能。

6.2 使用数据卷

方式一:直接使用命令来挂载 -v

 docker run -it -v 主机目录:容器目录

 # 测试
 docker run -it -v /home/ceshi:/home centos /bin/bash

 # 容器起来时候我们可以通过 docker inspect 容器id 来查看挂载状态
挂载状态
挂载状态

在容器内简历一个test.java测试文件。测试文件的同步,是一个双向绑定的过程。

双向绑定
双向绑定

6.3 实战:安装MySQL

# 获取镜像
camile@camile:/$ docker pull mysql:5.7

# 运行容器,需要做数据卷挂载 # 安装启动mysql -e表示配置环境
# 官方测试:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

# 启动我们的mysql
-d 后台运行
-p 端口映射
-v 卷挂载
-n 容器名字
camile@camile:~$ docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=zuiweizhiming666 --name mysql01 mysql:5.7

# 启动成功之后,我们在本地使用 navicat 来测试以下
# navicat 连接到服务器的3310 -3310和容器内的3306映射,这个时候我们就可以连接上了

# 在本地测试创建一个数据库,查看一下我们创建的路径是否ok
test
test
test
test

6.4 具名和匿名挂载

Docker中的匿名挂载和具名挂载是两种不同的数据卷挂载方式。

匿名挂载是指在启动容器时,只指定容器内的路径,而不指定宿主机的目录。这样会生成一个随机的宿主机挂载目录,可以通过 docker volume ls 命令查看。

具名挂载是指在启动容器时,既指定容器内的路径,又指定一个卷名作为宿主机的目录。 这样可以方便地找到和管理数据卷,也可以通过 docker volume inspect 卷名 命令查看详细信息。

匿名挂载和具名挂载的语法如下:

  • -v 容器内路径 # 匿名挂载

  • -v 卷名:容器内路径 # 具名挂载

下面是具名挂载和匿名挂载的相关命令代码块:

# 启动一个nginx容器,使用匿名挂载,将容器内的/etc/nginx目录挂载到宿主机上
docker run -d -P --name nginx01 -v /etc/nginx nginx

# 查看所有的数据卷
docker volume ls

# 启动一个nginx容器,使用具名挂载,将容器内的/etc/nginx目录挂载到宿主机上,并命名为juming-nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx

# 查看具体的数据卷信息
docker volume inspect juming-nginx

6.5 DockerFile

DockerFile 就是用来构建Docker镜像的构建文件、命令脚本,下面先体验一下!

通过这个脚本可以生成镜像,镜像是一层一层的,脚本是一个个的命令。

# 创建一个DockerFile文件,名字可以随机 ,建议 Dockerfile

# 文件中的内容
FROM centos

VOLUME ["volume01","volume02"]

CMD echo "---end---"
CMD /bin/bash

# 这里的每个命令,就是镜像的一层
# 启动自己写的容器
post image

这个目录就是我们生成镜像的时候自动挂载的数据卷目录。这个卷和外部一定有一个同步的目录。

post image

查看一下卷挂载的路径。

测试一下刚才的文件是否同步了。

post image

这种方式我们未来使用的十分多,因为我们通常会构建自己的镜像!假设构建镜像的时候没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径。


7.DockerFile

7.1 DockerFile

dockerFile 是用来docker镜像的文件,是命令参数脚本。

构建步骤:编写一个dockerfile文件

  1. docker build 构建成一个镜像

  2. docker run 运行镜像

  3. docker push 发布镜像

7.2 dockerFile构建过程

基础知识

  1. 每个保留关键字都是大写字母

  2. 执行从上到下执行

  3. #表示注释

  4. 每一个指令都会创建提交一个新的镜像层,并提交!

dockerfile
dockerfile

dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单。

Docker镜像逐渐成为企业交付的标准,必须要掌握。

步骤:

DockerFile:构建文件,定义了一切的步骤,源代码

DockerImages:DockerFile构建生成的镜像,最终发布和运行的产品,原来是 jar war。

Docker容器:容器就是镜像运行起来提供服务的。

7.3 DockerFile指令

知晓了DockerFile命令,我们就可以自己制作镜像:

FROM          # 基础镜像,一切从这里开始构建
MANITAINER    # 镜像是谁写的 姓名+邮箱
RUN           # 镜像构建的时候需要运行的命令
ADD           # 步骤,tomcat镜像,这个tomcat压缩包!添加内容
WORKDIR       # 镜像的工作目录
VOLUME        # 挂载的目录
EXPOSE        # 指定暴露端口
CMD           # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT    # 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD       # 当个构建一个被继承dockerfile 的时候,会运行这个指令,触发指令
COPY          # 类似ADD,将我们文件拷贝到镜像中
ENV           # 构建的时候设置环境变量

7.4 实战测试

Docker Hub 中绝大多数镜像都是从这个基础镜像过来的 FROM scratch,然后配置需要的软件和配置来进行的构建。

创建一个自己的Centos

# 1.编写DockerFile的文件
FROM centos:7

MAINTAINER qiaowei<454921269@qq.com>

ENV MYPATH /usr/local

WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "---end---"
CMD /bin/bash

# 2.通过这个文件构建镜像
# 命令 docker build -f dockerfile文件路径 -t 镜像名:[tag]
Successfully built 11a9535c2896
Successfully tagged mycentos:0.1

# 3.测试运行
root@camile:/home/dockerfile# docker run -it 11a9535c2896
[root@f9c5dbcee829 local]# pwd
/usr/local
[root@f9c5dbcee829 local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.6  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:06  txqueuelen 0  (Ethernet)
        RX packets 23  bytes 2804 (2.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@f9c5dbcee829 local]# vim test

自己写的centos 添加了vim 和 net-tools ,测试成功!

我们可以列出本地镜像的变更历史

root@camile:/home/dockerfile# docker history 11a9535c2896
IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
11a9535c2896   4 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B        
5005cf751c81   4 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
21407997234d   4 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
a567cd94200e   4 minutes ago   /bin/sh -c #(nop)  EXPOSE 80                    0B        
48ad5b128e9a   4 minutes ago   /bin/sh -c yum -y install net-tools             161MB     
da7d8a18d88e   4 minutes ago   /bin/sh -c yum -y install vim                   216MB     
b1524097a173   4 minutes ago   /bin/sh -c #(nop) WORKDIR /usr/local            0B        
01282534605d   4 minutes ago   /bin/sh -c #(nop)  ENV MYPATH=/usr/local        0B        
9bb0de5c2898   4 minutes ago   /bin/sh -c #(nop)  MAINTAINER qiaowei<454921…   0B        
eeb6ee3f44bd   5 months ago    /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B        
<missing>      5 months ago    /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B

7.5 tomcat镜像

  1. 准备镜像文件 tomcat 压缩包,jdk的压缩包。

jdk
jdk
  1. 编写dockerfile文件,官方命名“Dockerfile”,build会自动寻找这个文件,就不需要 -f 指定了。

    root@camile:/home/qiaowei/build/tomcat# touch readme.txt
    root@camile:/home/qiaowei/build/tomcat# vim Dockerfile
    
    # 自己制作Dockerfile
    FROM centos:7
    MAINTAINER qiaowei<454921269@qq.com>
    
    COPY readme.txt /usr/local/readme.txt
    
    ADD jdk-17_linux-x64_bin.tar.gz /usr/local/
    ADD apache-tomcat-9.0.59.tar.gz /usr/local/
    
    RUN yum -y install vim
    
    ENV MYPATH /usr/local
    WORKDIR $MYPATH
    
    ENV JAVA_HOME /usr/local/jdk-17.0.2
    ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
    ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.59
    ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.59
    ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
    
    EXPOSE 8080
    
    CMD /usr/local/apache-tomcat-9.0.59/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.59/bin.logs/catalina.out
    
  2. 构建镜像

    # docker build -t diytomcat .
    
构建镜像
构建镜像

1.

  1. 运行容器:

    docker run -d -p 9090:8080 --name qiaoweitomcat -v /home/qiaowei/build/tomcat/test:/usr/local/apache-tomcat-9.0.59/webapps/test -v /home/qiaowei/build/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.59/logs diytomcat
    
  2. 访问测试

tomcat
tomcat
  1. 发布项目(由于做了卷挂载,我们直接在本地编写项目就可以)

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
              http://java.sun.com/xml/ns/javaee/web-app_4_0.xsd"
               version="4.0">
    </web-app>
    
  2. 随便写一个html文件,测试访问

    <!DOCTYPE html>
    <html>
        <head>
             <meta charset="UTF-8"/>
            <title>这是个标题</title>
        </head>
        <body>
            <h1>这是一个一个简单的HTML</h1>
            <p>Hello World!</p>
        </body>
    </html>
    
html
html

7.6 发布自己的镜像

Dockerhub

  1. 地址:https://hub.docker.com/,注册自己的账号

  2. 确定这个账号可以登录

  3. 在我们服务器上提交自己的镜像

    Usage:  docker login [OPTIONS] [SERVER]
    
    Log in to a Docker registry.
    If no server is specified, the default is defined by the daemon.
    
    Options:
      -p, --password string   Password
          --password-stdin    Take the password from stdin
      -u, --username string   Username
    
  4. 登录完毕后可以提交镜像了

    # 先给镜像打一个标签
    docker tag 1ba62e6aa598 wulegekong/tomcat:1.0
    
    # 提交镜像
    docker push wulegekong/tomcat:1.0
    
    # 注意:镜像名前一定是自己dockerhub的用户名,否则会拒绝push请求
    

7.7 发布镜像到阿里云容器服务

  • 登录阿里云

  • 找到容器镜像服务

  • 创建命名空间

  • 根据官方提供的操作指南操作即可。


8.Docker网络

我们使用 ip addr 命令查看本机的所有网络信息:

ip addr
ip addr

这里出现了docker0地址,下面简单理解一下docker网络的原理:

  1. 我们每安装一个docker容器,docker就会给docker容器分配一个ip,只要电脑安装了docker,就会有一个网卡docker0桥接模式,使用的是evth-pair技术。

  2. 再次测试ip addr

  3. 再启动一个容器测试,发现又多了一对网卡

# 我们发现这个容器带来网卡,都是一对一对的 
# evth-pair 就是一对的虚拟设备接口,它们是成对出现的,一端连着协议,一段彼此相连。 
# 正因为有这个特性,evth-pair充当一个桥梁,连接各种虚拟网络设备 
# openstac,Docker容器之间的连接 ovs的连接都是使用evth-pair技术
  1. 我们来测试tomcat01和tomcat02这两个之前创建的容器是否可以相互ping通,能够ping通!

网络
网络

结论:tomcat01和tomcat02是公用的一个路由器,docker0.

所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用IP。

小结

Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥 docker0。

网络
网络

Docker中的所有的网络接口都是虚拟的,虚拟的转发效率高,只要容器删除,对应网桥一对就没了。


9.总结

笔者仅仅简单地学习和应用了Docker的一些基本内容,勉强算是入门,后续会学习Docker-Compose等进阶内容,敬请期待。