Docker入门


安装 Docker

1、卸载旧的版本

yum remove docker \
    docker-client \
    docker-client-latest \
    docker-common \
    docker-1atest \
    docker-latest-logrotate \
    docker-logrotate \
    docker-engine

2、下载需要安装的包

yum install -y yum-utils

3、设置镜像仓库

# 推荐使用国内的镜像
yum-config-manager \
    --add-repo \
    http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

4、更新yum软件包索引

yum makecache fast

5、安装docker

# docker-ce 社区版  ee 企业版
yum install docker-ce docker-ce-cli containerd.io

6、启动docker

systemctl start docker

# 验证是否启动成功
docker version

7、运行Hello-world

docker run hello-world

8、卸载docker

# 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io

# 删除资源文件
rm -rf /var/lib/docker

Docker run的运行流程

  • docker首先在本机寻找镜像,判断本机是否存在这个镜像
  • 如果有这个镜像,则使用此镜像运行;如果没有,则去docker hub 上下载镜像
  • 在docker hub 上是否能找到此镜像
  • 如果找到,则下载镜像到本地并运行;如果没有找到,则返回错误

Docker 底层原理

docker是如何进行工作的

Docker是一个Client - Server结构的系统,Docker的守护进程运行在主机上。通过Socket从客户端访问。DockerServer接收到Docker-Client的指令,就会执行这个命令新建docker容器

docker为什么比vm快

Docker有着比虚拟机更少的抽象层。
docker利用的是宿主机的内核,vm需要是Guest Os。

所以说,新建一个容器的时候,docker不需要像虚拟机一样重新加载一个操作系统内核,避免引导。虚拟机是加载Guest oS ,分钟级别的,而docker是利用宿主机的操作系统吗,省略了这个复杂的过程,秒级!

Docker 常用命令

帮助命令

docker version      # 查看docker版本 
docker info         # 查看docker详细信息
docker --help       # 查看docker的所有命令
docker 命令 --help  # 查看docker某个命令的参数信息

镜像命令

docker images】 查看本地主机上的所有镜像

# 可选参数

-a,--all   # 列出所有镜像
-q,--quiet # 只显示镜像的id
  

[root@zerollone ~]# docker images
REPOSITORY                TAG       IMAGE ID       CREATED        SIZE
postgres                  latest    a373cbdcfe8b   2 weeks ago    418MB
# 解释说明
REPOSITORY  镜像的仓库源
TAG         镜像的标签
IMAGE ID    镜像的id
CREATED     镜像的创建时间
SIZE        镜像的大小

docker search】 搜索镜像

[root@zerollone ~]# docker search mysql
NAME                            DESCRIPTION                                      STARS     OFFICIAL   AUTOMATED
mysql                           MySQL is a widely used, open-source relation…   14487     [OK]       
mariadb                         MariaDB Server is a high performing open sou…   5529      [OK]       
percona                         Percona Server is a fork of the MySQL relati…   621       [OK]

# 命令可选项,通过搜索来过滤
--fiter=STARS=3000  # 搜索STARS大于3000的镜像

[root@zerollone ~]# docker search mysql --filter=STARS=3000;
NAME      DESCRIPTION                                      STARS     OFFICIAL   AUTOMATED
mysql     MySQL is a widely used, open-source relation…   14487     [OK]       
mariadb   MariaDB Server is a high performing open sou…   5530      [OK]

docker pull】 下载镜像

# 下载镜像  
# docker pull 镜像名[:tag]  tag表示版本
[root@zerollone ~]# docker pull mysql
Using default tag: latest           # 如果不写tag,默认是latest,最新版本   
latest: Pulling from library/mysql
5262579e8e45: Pull complete         # 分层下载,docker image 的核心,联合文件系统
741b767e25b7: Pull complete 
06e0c37837cf: Pull complete 
c6f5d3670db7: Pull complete 
d5c567b29c3e: Pull complete 
6effcc6561c9: Pull complete 
1e1493d45d9c: Pull complete 
7101609fa7d9: Pull complete 
432a1261dc2a: Pull complete 
865a24d6d1f2: Pull complete 
Digest: sha256:566007208a3f1cc8f9df6b767665b5c9b800fc4fb5f863d17aa1df362880ed04 # 签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest      # 下载的真实地址


# 下面的命令等价
docker pull mysql
docker pull docker.io/library/mysql:latest


# 指定版本下载
[root@zerollone ~]# docker pull mysql:8.0
8.0: Pulling from library/mysql
5262579e8e45: Already exists    # 与前面下载的镜像共用的文件
741b767e25b7: Already exists 
06e0c37837cf: Already exists 
c6f5d3670db7: Already exists 
d5c567b29c3e: Already exists 
323a74fdf36b: Pull complete 
130e11b8eb71: Pull complete 
e92f1f2dd77c: Pull complete 
43c0f03962c9: Pull complete 
6194c2f9ce13: Pull complete 
a235a73ec4d4: Pull complete 
Digest: sha256:a7a96a9dbf6f310703c4e0c61086b23c5835c33a05544cdc952a7cd0b8feb675
Status: Downloaded newer image for mysql:8.0
docker.io/library/mysql:8.0

docker rmi】 删除镜像

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

容器命令

说明:有了镜像才可以创建容器,下载一个centos镜像来测试学习,docker pull centos

新建容器并启动

docker run [可选参数] imageName

# 参数说明
--name="name"   # 设置容器名字,用来与其他容器进行区分
-d              # 以后台的方式运行
-it             # 使用交互式方式运行, 进入容器查看内容
-p              # 小写,指定容器的端口,-p 主机端口:容器端口
-P              # 大写,随机指定端口

# 启动并进入容器
docker run -it centos /bin/bash

# 退出容器
exit

列出所有的运行的容器

docker ps  列出所有正在运行的容器

# 参数说明
-a      # 列出当前正在运行的容器 + 历史运行的容器
-n=x    # 列车最近运行的前x个容器
-q      # 只显示容器的编号

退出容器

exit         # 停止并退出容器
ctrl + p + q # 不停止但退出容器

删除容器

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

启动重启停止杀死容器

docker start 容器id         # 启动容器
docker restart 容器id       # 重启容器
docker stop 容器id          # 停止正在运行的容器
docker kill 容器id          # 强制停止运行的容器

其他常用命令

后台启动容器

  • docker run -d 容器id
docker run -d centos

# 启动后,运行 docker ps,发现 centos 停止并未运行
# 问题原因:
#   docker 容器使用后台运行,就必须要有一个前台进程,docker 发现没有应用就会自动停止。

查看日志

  • docker logs
# 参数说明
#    -f         显示全部日志 
#    -t         显示日志的时间戳
#    -n number  需要显示的日志条数,此命令等价于 --tail number

# 在centos中循环打印
docker run -d centos /bin/bash -c "while true;do echo hello;sleep 1;done"

# 查看centos容器的日志信息
docker logs -tf -n 10 容器id
docker logs -tf --tail 10 容器id

查看容器中进程信息

  • docker top
# 命令  docker top 容器id

[root@zerollone ~]# docker top 3095
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
799                 1466                2663                0                   10:25               ?                   00:00:00            /bin/bash ********
799                 2097                2663                0                   10:26               ?                   00:00:00            /bin/bash ********
799                 2605                2586                0                   Sep17               ?                   00:00:00            /bin/bash ********

# 说明:
    UID:当前用户id
    PID:当前进程id 
    PPID:父进程id

查看镜像元数据

  • docker inspect 镜像/容器id
[root@zerollone ~]# docker inspect 5d0da3dc9764
[
    {
        "Id": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6",
        "RepoTags": [
            "centos:latest"
        ],
        "RepoDigests": [
            "centos@sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2021-09-15T18:20:05.184694267Z",
        "Container": "9bf8a9e2ddff4c0d76a587c40239679f29c863a967f23abf7a5babb6c2121bf1",
        "ContainerConfig": {
            "Hostname": "9bf8a9e2ddff",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"/bin/bash\"]"
            ],
            "Image": "sha256:f5b050f177fd426be8fe998a8ecf3fb1858d7e26dff4080b29a327d1bd5ba422",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.build-date": "20210915",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS"
            }
        },
        "DockerVersion": "20.10.7",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/bash"
            ],
            "Image": "sha256:f5b050f177fd426be8fe998a8ecf3fb1858d7e26dff4080b29a327d1bd5ba422",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.build-date": "20210915",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS"
            }
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 231268856,
        "VirtualSize": 231268856,
        "GraphDriver": {
            "Data": {
                "MergedDir": "/var/lib/docker/overlay2/cbf06b7f65308cab4597b5ee427702f2f4f9a87fd62b24937387681576134eb4/merged",
                "UpperDir": "/var/lib/docker/overlay2/cbf06b7f65308cab4597b5ee427702f2f4f9a87fd62b24937387681576134eb4/diff",
                "WorkDir": "/var/lib/docker/overlay2/cbf06b7f65308cab4597b5ee427702f2f4f9a87fd62b24937387681576134eb4/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

进入当前正在运行的容器
容器通常都是使用后台方式运行的,可能需要经常进入容器进行一些相关配置,进入正在运行的容器有两种命令

  • docker exec -it 容器id bashshell
  • docker attach 容器id

第一种方式:

[root@zerollone ~]# docker run -d centos /bin/bash -c "while true;do echo hello;sleep 100;done;"
28fc1a2e10e344fd72d771ac02840f72a4ba1ab24b4e4707e3302c4f2f423c6a

[root@zerollone ~]# docker ps
CONTAINER ID   IMAGE                     COMMAND                   CREATED         STATUS         PORTS                                                                                                                                                                                            NAMES
28fc1a2e10e3   centos                    "/bin/bash -c 'while…"   4 seconds ago   Up 3 seconds                                                                                                                                                                                                    epic_proskuriakova

# 进入容器
[root@zerollone ~]# docker exec -it 28fc1a2e10e3 /bin/bash

[root@28fc1a2e10e3 /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

第二种方式:

[root@zerollone ~]# docker attach 28fc1a2e10e3
hello
hello
hello

docker exec 和 docker attach 的区别

  • docker exec 进入容器后开启一个新的终端,可以在里面进行命令操作
  • docker attach 进入容器中正在执行的终端,不会启动新的进程

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

  • docker cp 容器id:文件路径 物理机文件路径
# 进入docker容器
[root@zerollone ~]# docker run -it centos /bin/bash
[root@038f00b63edf /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@038f00b63edf /]# cd home/
[root@038f00b63edf home]# touch test.java
[root@038f00b63edf home]# ls
test.java

# 切换到本机
[root@zerollone ~]# ls
data  docker-compose.yml  thingsboard-3.4.4.rpm
[root@zerollone ~]# docker ps
CONTAINER ID   IMAGE                     COMMAND                   CREATED              STATUS              PORTS                                                                                                                                                                                            NAMES
038f00b63edf   centos                    "/bin/bash"               About a minute ago   Up About a minute                                                                                                                                                                                                    awesome_banzai

# 拷贝容器文件
[root@zerollone ~]# docker cp 038f00b63edf:/home/test.java /root
                                               Successfully copied 1.54kB to /root
[root@zerollone ~]# ls
data  docker-compose.yml  test.java  thingsboard-3.4.4.rpm

可视化

  • portainer
  • Rancher

什么是portainer
Docker图形化界面管理工具,提供一个后台面板供用户操作

# 命令
docker run -d -p 10003:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

测试访问:http://ip:10003

Docker 镜像详解

镜像是什么

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

所有的应用,直接打包成docker镜像,就可以直接跑起来。

Docker镜像加载原理

UnionFS 联合文件系统

UnionFS(联合文件系统),联合文件系统是一种分层,轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。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等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。

分层理解

通过下载一个镜像,观察下载日志的输出,可以看到镜像是一层一层被下载。

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

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

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

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

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

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

下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。

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

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

Docker在 Windows上仅支持windowsfilter一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW。

下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。

特点

  • Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部
  • 这一层就是我们通常说的容器层,容器之下的都叫镜像层!

commit镜像

提交一个自己的镜像,将自己主机里docker中的容器提交成一个新的版本。

  • docker commit
# 具体命令
docker commit -m="提交容器的描述信息" -a="作者名" 容器id 镜像名:[tag]

容器数据卷

什么是容器卷

容器之间可以有一个数据共享的技术,docker容器中产生的数据,同步到本地,这就是卷技术,目录的挂载,将容器内的目录挂载到Linux中。

容器的持久化和同步操作,容器间也是可以数据共享的

使用数据卷

方式一:使用-v命令进行挂载
  • docker run -it -v 主机目录地址:容器内目录地址 ….
# 测试
[root@zerollone ~]# pwd
/root
[root@zerollone ~]# ls
data  docker-compose.yml  test.java  thingsboard-3.4.4.rpm

# 挂载
[root@zerollone ~]# docker run -it -v /root/centos_file:/home centos /bin/bash

# 容器内
[root@617b5b813dfc /]# cd home
[root@617b5b813dfc home]# ls
[root@617b5b813dfc home]# touch a.txt
[root@617b5b813dfc home]# ls
a.txt
[root@617b5b813dfc home]# exit
exit

# 主机内
[root@zerollone ~]# ls
centos_file  data  docker-compose.yml  test.java  thingsboard-3.4.4.rpm
[root@zerollone ~]# cd centos_file/
[root@zerollone centos_file]# ls
a.txt

可以通过docker inspect命令查看容器的挂载目录信息

使用数据卷是一个双向绑定的操作。即不论在容器内外操作文件,都会看到文件相应的变化

# 主机内
[root@zerollone centos_file]# cat a.txt 
[root@zerollone centos_file]# vim a.txt 
[root@zerollone centos_file]# cat a.txt 
hello docker!!!
[root@zerollone centos_file]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS         PORTS     NAMES
617b5b813dfc   centos    "/bin/bash"   30 minutes ago   Up 8 minutes             suspicious_villani

# 进入容器
[root@zerollone centos_file]# docker exec -it 617b5b813dfc /bin/bash
[root@617b5b813dfc /]# cd home/
[root@617b5b813dfc home]# cat a.txt 
hello docker!!!
[root@617b5b813dfc home]# 

安装MySQL

  • 获取镜像
    docker pull mysql:5.7

  • 运行容器,做数据挂载。同时启动mysql时,需要配置密码
    docker run -d -p 3306:3306 -v /root/mysql/conf:/etc/mysql/conf.d -v /root/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 –name mysqlTest mysql:5.7

说明:
-e 环境配置

匿名与具名挂载

匿名挂载
  • -v 容器内路径
  • 命令例子:docker run -d -P –name nginx01 -v /etc/nginx nginx

上面的命令就是匿名挂载,-v只写了容器内的路径,没有写容器外的路径

查看容器中数据卷的情况

具名挂载
  • docker run -d -P –name nginx2 -v nginxTestFile:/etc/nginx nginx

通过 -v 卷名:容器内路径来实现具名挂载

所有的docker容器内的卷,没有指定目录的情况下都是在目录/var/lib/docker/volumes/xxxxx/_data

可以通过具名挂载方法方便找到一个卷,大多数情况都使用具名挂载

-v 容器内路径           #匿名挂载
-v 卷名:容器内路径      # 具名挂载
-v 主机路径:容器内路径  # 指定路径挂载

拓展:

通过 -v 容器内路径:ro/rw 来改变读写权限
ro readonly 只读
rw readwrite 读写

一旦设置了容器权限,容器对挂载出来的内容就存在限定。ro表示此路径只能通过宿主机来操作,容器内部是无法进行操作的。
docker run -d -P –name nginx01 -v nginx_1_file:/etc/nginx:ro nginx
docker run -d -P –name nginx02 -v nginx_2_file:/etc/nginx:rw nginx


文章作者: zerollone
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 zerollone !
  目录