docker

介绍

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。

本文不对docker进行深层次解剖,仅记录docker一些基本使用以及常用用法。

docker工作原理简析:

​ cs结构,docker守护进程运行在主机上,通过socket从客户端访问。
​ dockerserver接受到docker client指令,就执行该指令。

docker与虚拟机

docker是一款虚拟化容器工具,类似于vmware,与vmware不同的是,docker是进程隔离界别的虚拟化工具,而vmware是系统级别的虚拟化工具,docker较于vmware要轻量级的多。docker有比虚拟机更少的抽象层。docker 利用的是宿主机的内核,vm每个镜像需要一个内核(guest os)

image-20211108111007180

docker安装

这里只记录了常用linux发行版的docker安装,其他安装参考官方文档

官方文档:https://docs.docker.com/get-docker/、

centos

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
	
删除旧版本:
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

sudo yum install -y yum-utils
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
#如果没有vpn可以换成国内镜像例如阿里云:
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io
#docker-ce为社区版,ee为企业版

其他安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
docker centos6.x安装:
一般官方都需要centos7以上才能安装,yum包也只支持7,如果6要安装,需升级内核
1.yum安装带aufs模块的3.10内核
1、cd /etc/yum.repos.d
2、wget http://www.hop5.in/yum/el6/hop5.repo
3、yum install kernel-ml-aufs kernel-ml-aufs-devel
2.修改grub的主配置文件/etc/grub.conf,设置default=0,表示第一个title下的内容为默认启动的kernel(一般新安装的内核在第一个位置)。
3、重启系统,这时候你的内核就成功升级了。
[root@localhost ~]# uname -r
3.10.5-3.el6.x86_64
查看内核是否支持aufs:
[root@localhost ~]# grep aufs /proc/filesystems
nodev aufs
epel方式安装:
在Fedora EPEL源中已经提供了docker-io包,下载安装
rpm -ivh http://mirrors.sohu.com/fedora-epel/6/x86_64/epel-release-6-8.noarch.rpm
yum安装docker-io:
yum -y install docker-io
以守护进程模式启动docker
docker -d
rpm方式安装:
curl -O -sSL https://get.docker.com/rpm/1.7.1/centos-6/RPMS/x86_64/docker-engine-1.7.1-1.el6.x86_64.rpm
rpm -Uvh docker -engine -1.7.1-1.el6.x86_64.rpm --nodeps
yum -y install libcgroup
service docker start


docker镜像源: #可以不设置
/etc/docker/daemon.json:
{
"registry-mirrors": [
"https://yourid_xxx.mirror.aliyuncs.com",
"https://reg-mirror.qiniu.com/",
"http://hub-mirror.c.163.com"
],
"insecure-registries": [],
"debug": true,
"experimental": false
}

卸载

Uninstall Docker Engine
 sudo yum remove docker-ce docker-ce-cli containerd.io
#/var/lib/docker docker的默认工作路径
 sudo rm -rf /var/lib/docker
 sudo rm -rf /var/lib/containerd

使用阿里云容器镜像加速器

阿里云-管理后台-(搜索)容器镜像服务-镜像工具-镜像加载器
加载器地址;https://9eguah0s.mirror.aliyuncs.com
通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://9eguah0s.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

docker使用

docker三要素

docker由三部分组成:image(镜像)、容器(container)、仓库(repository)

img

其工作流程大致为,当用户需要启动一个镜像时,用户从客户端发送命令(通过socket)到服务端,然后服务端从仓库拉取一个镜像(一般有远程仓库和本地仓库),然后将镜像实例化成容器(也就是启动镜像)。

简单来说就是从仓库拿镜像,拿到镜像启动。

docker命令

帮助命令:

1
2
3
docker version 显示docker版本信息
docker info 纤细docekr系统inxi,包括镜像和容器的数量
docker [命令] --help 帮助

镜像命令:

基本上最常用的就是查看本地仓库镜像,搜索镜像,以及删除镜像。(docker pull)是将镜像从远程拉取到本地

    docker images: 查看本地镜像
        
        REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
        ubuntu       latest    c29284518f49   8 days ago   72.8MB
        REPOSITORY:  镜像的仓库源
        TAG: 	镜像的标签
        IMAGE ID: 镜像id
        CREATED:	创建时间
        SIZE:	大小
        
    -a,--all 列出所有镜像
    -q,--quiet 只显示镜像的id
    
    docker search :
    搜索镜像 docker search [package]
    --filter=STARS=[NUMBER] 搜索大于多少星星的镜像
    docker pull:
    下载镜像 docker pull [package]
    如果不写tag 默认为latest
    
    docker rmi :	删除镜像
    可以通过id或者镜像名称删除镜像
    docker rmi -f $(docker images -aq)删除所有镜像

容器命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
docker pull [images]  创建容器
docker run [option] image 创建并启动容器
参数:
--name="name" 容器名字
-d 后台方式运行,
-it 使用交互运行,进入容器查看内容
-p 指定容器端口 -p 8080:8080
-p 主机端口:容器端口
-p 容器端口
容器端口
-P 随机指定端口
例:
docker run -it centos /bin/bash
此时就进入了容器,exit可以退出

docker ps 列出所有正在运行容器
docker ps -a 列出所有容器
docker ps -n=NUMBER 显示最近创建的几个容器 number为个数
docker ps -q:只显示容器的编号

退出容器:
exit 直接退出
ctrl + P + Q 容器不停止退出
删除容器:
docker rm 容器id 删除指定容器,不能删除正在运行的容器,强制删除 rm -filter
docker rm -f $(docker ps -aq) 删除所有
docker ps -a -q | xargs docker rm 删除所有容器

启动和停止容器:
docker start 容器id
docker restart
docker stop
dokcer kill

常用其他命令:
后台启动容器:
docker run -d 镜像名
#后台启动容器
docker run -d ubuntu
此时docker ps ,发现容器停止运行了
#常见的坑:docker容器使用后台运行,就必须要有要一个前台进程,docker发现没有应用,就会自动停止
# nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了查看容器中进程信息:
docker top 容器id
查看镜像的元数据:
docker inspect 容器id
进入当前正在运行的容器:
docker exec -it 容器id bashShell
#docker exec -it df36 /bin/sh
docker attach -it 容器id bashshell
-it是交互模式运行,bashshell表示进入容器需要使用的shell,例如这里是ubuntu就使用/bin/bash 或者/bin/sh,如是普通应用也可以不写,表示进入不执行任何命令
exec是进入容器后开启一个新的终端,attach是进入容器中正在运行的终端,不会启动新的进程(tty终端)

从容器内将文件拷贝到主机上:
docker cp 容器id:源文件目录 目标目录

日志命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
查看日志:
docker logs 容器id
docker logs -tf --taill [number] 容器id
-tf 显示日志
--tail number 显示指定行数的日志(tail为持续打印到屏幕)

docker logs [OPTIONS] CONTAINER
Options:
--details 显示更多的信息
-f, --follow 跟踪实时日志
--since string 显示自某个timestamp之后的日志,或相对时间,如42m(即42分钟)
--tail string 从日志末尾显示多少行日志, 默认是all
-t, --timestamps 显示时间戳
--until string 显示自某个timestamp之前的日志,或相对时间,如42m(即42分钟)

commit镜像

​

1
2
3
docker commit 提交容器成为一个新的副本
docker commit -m="提交的描述信息" -a="作者" 容器id 目标容器名:[TAG]
#将容器提交为镜像

Admin@123

实例

nginx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
	[root@www ~]#docker pull nginx
在docker官方搜索nginx镜像可以获取到帮助文档
[root@www ~]# docker run -d --name nginx01 -p3333:80 nginx

ea16179cef0927527031c01dffd01af4c339281a69537f5f7424fdb7b56c134c
[root@www ~]#
[root@www ~]#
[root@www ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ea16179cef09 nginx "/docker-entrypoint.…" 3 seconds ago Up 1 second 0.0.0.0:3333->80/tcp, :::3333->80/tcp nginx01
[root@www ~]# docker exec -it nginx01 /bin/bash
root@ea16179cef09:/#
root@ea16179cef09:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@ea16179cef09:/# cd /etc/nginx/
root@ea16179cef09:/etc/nginx# ls
conf.d fastcgi_params mime.types modules nginx.conf scgi_params uwsgi_params
root@ea16179cef09:/etc/nginx# curl localhost:80
<!DOCTYPE html>
<html>
#中间为nginx默认首页,此处省略
</html>
[root@www ~]# curl localhost:3333
<!DOCTYPE html>
<html>
#中间为nginx默认首页,此处省略
#这里在容器内nginx配置文件为/etc/nginx,与正常yum安装路径一致,外面根据run时配置为3333端口,所以访问也是3333端口,容器内部端口为80,所以在里面访问也是80端口。这里为容器内外端口映射

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

(这里其容器内部有bash命令环节,如果没有可以直接在外面复制。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@iZbp1buq0r8g0gh1hp49qwZ ~]# docker exec -it 5265 /bin/sh #(如果只是进入用exec也行,得先判断要进入的容器是否有正在运行的终端,例如跑的是一个web应用服务程序,可能前台终端就正在运行其日志,这个时候还是得用exec,并且在最后加上参数/bin/sh,这样不会影响到正在运行docker程序)
/opt/solo #
/opt/solo # ls
CHANGE_LOGS.md js log4j2.xml repository.json static-site
META-INF lang_en_US.properties manifest.json.tpl robots.txt sw.js
admin lang_zh_CN.properties markdowns scss
common-template latke.properties opensearch.xml skins
error lib org solo.properties
images local.properties plugins static-resources.xml
/opt/solo # ps
PID USER TIME COMMAND
1 root 49:04 java -cp lib/*:. org.b3log.solo.Server --listen_port=8080 --server_scheme=http --server_host=localhost --serve
22054 root 0:00 /bin/sh
22060 root 0:00 ps
/opt/solo # touch ceshi.file
/opt/solo # exit
[root@iZbp1buq0r8g0gh1hp49qwZ ~]# docker cp 5265:/opt/solo/ceshi.file ./
[root@iZbp1buq0r8g0gh1hp49qwZ ~]# ll
total 2956924
-rw-r--r-- 1 root root 24 Dec 9 2020 1.sh
-rw-r--r-- 1 root root 207105 Dec 3 2020 acme.sh
-rw-r--r-- 1 root root 0 Jul 26 16:44 ceshi.file

centos

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@www /]# docker run -it centos:latest
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
a1d0c7532777: Pull complete
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest


[root@1fb87f8fb8e4 /]# cat /etc/redhat-release
CentOS Linux release 8.4.2105
[root@1fb87f8fb8e4 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@1fb87f8fb8e4 /]#

这里使用run会自动拉取镜像(如果本地仓库没有镜像),然后启动,-it为前台运行。

需要注意的点

1.运行docker进程时,如果像centos这种只能前台启动的容器必须加上-it参数,否则默认为后台运行,而centos无法后台运行,而docker如果没有主进程在前台运行则会自动停止容器。

2.一般一个容器为一个应用程序,且必须有一个常驻运行的进程,参考第一点。

3.run的功能是镜像实例化成容器,但如果本地没有镜像,会自动从远程拉取。

4.容器的文件系统和本机是隔离的,如果担心数据因容器遗失可以将容器某个目录位置映射到本机上,实现数据共享。如果想要直接在本机可以随时查看容器内日志也可以这样做。

可视化(portainer)

portainer
Rancher(CI/CD)
portainer:docker图形化管理工具
安装:
docker run -d -p 9000:9000 -v /root/portainer:/data -v /var/run/docker.sock:/var/run/docker.sock –name dev-portainer portainer/portainer

image-20211112171827368

访问:ip+port(9000),第一次登陆设置用户名密码

image-20211112171938663

(就是一个docker图形管理工具,无需专门学习)

docker文件系统

docker底层使用的是一种叫UnionFS(联合文件系统)的文件系统。

union文件系统是一种分层,轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件下。union文件系统是docker镜像的基础。镜像可以通过分层来集成,基于基础镜像,可以制作各种具体的应用镜像。
提醒:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会吧各底层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录

docker镜像加载原理

1
2
3
4
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统unionFS
bootfs主要包含bootloader和kernel,linux刚启动时会加载bootfs文件系统,在docker镜像的最底层是bootfs。这一层与我们典型的linux系统是一样的,包含boot加载器和内核,当boot加载完成之后整个内核都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs,在bootfs之上,包含的就是典型linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如ubuntu ,centos。
docker中安装的linux镜像(centos,ubuntu)相对于正常使用的系统要小得多。因为其作为一个精简的os,rootfs很小,只包含最基本的命令,工具和程序库,其底层直接用host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发新版可以共用bootfs

容器数据卷

docker的理念回顾
如果数据都在容器中,那么我们容器删除,数据就会丢失
需求:数据持久化
例如mysql,容器删除,数据就没了
容器之间可以有一个数据共享的技术。docker容器中产生的数据,同步到本地。
这就是卷技术。目录的挂载,将容器内的目录,挂载到linux上面。
容器数据卷:容器的持久化和同步操作,容器间也是可以数据共享的。

使用数据卷:
docker run -it -v 主机目录:容器内目录

测试

        docker run -it -v /home/ceshi:/home centos /bin/bash
    启动后可以通过docker inspect 容器id查看容器信息:
                 "Mounts": [
                {
                    "Type": "bind",
                    "Source": "/home/ceshi",
                    "Destination": "/home",
                    "Mode": "",
                    "RW": true,
                    "Propagation": "rprivate"
                }
            ],
            
    在容器内home目录中touch一个文件:
    [root@03ae6ed3870c home]# touch ceshi
    在本机/home/ceshi中查看:
    [root@www ceshi]# ll
    total 0
    -rw-r--r-- 1 root root 0 Aug  4 00:01 ceshi
    #即使容器删除时该文件依然在本机存在,所以这里非挂载,而是数据同步。

实例:安装mysql

docker pull mysql:5.7
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=123456 --name mysql01 mysql:5.7
-d 后台运行
-p 端口映射
-v 卷挂载
-e 环境配置
--name 容器名字

具名和匿名挂载

具名和匿名挂载是指容器卷是否有挂载名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
匿名挂载:
docker -v 容器内路径 匿名挂载:
-v 卷名:容器内路径 具名挂载
-v /宿主机路径:容器内路径 指定路径挂载

匿名挂载实例: nginx
docker run -d -P --name nginx01 -v /etc/nginx nginx
#这里只写了容器内路径,但没有写容器外路径
docker volume ls #查看匿名挂载
DRIVER VOLUME NAME
local 67893edc86b502ec91342bed2dff23f1ea01f67bc368a42e250ea37dc7e9c56a
local b004ad49f0207dfbbeca19fc428b7087f40af488bcf62b5c627c4bca087fdf06
local fc7d739c835251dc6a0994c4b5f25e5087524b6565d0b19989835c889d06ec4d
# 这里如果不知道容器对应匿名挂载id,可以通过docker inspect先查看容器信息,找到里面的挂载id。
[root@www ~]# docker volume inspect fc7d739c835251dc6a0994c4b5f25e5087524b6565d0b19989835c889d06ec4d
[
{
"CreatedAt": "2021-07-28T01:28:57-07:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/fc7d739c835251dc6a0994c4b5f25e5087524b6565d0b19989835c889d06ec4d/_data",
"Name": "fc7d739c835251dc6a0994c4b5f25e5087524b6565d0b19989835c889d06ec4d",
"Options": null,
"Scope": "local"
}
]
#查看该匿名挂载信息
[root@www ~]# ll /var/lib/docker/volumes/b004ad49f0207dfbbeca19fc428b7087f40af488bcf62b5c627c4bca087fdf06/_data/
total 24
drwxr-xr-x 2 root root 26 Aug 4 00:34 conf.d
-rw-r--r-- 1 root root 1007 Jul 6 07:59 fastcgi_params
-rw-r--r-- 1 root root 5290 Jul 6 07:59 mime.types
lrwxrwxrwx 1 root root 22 Jul 6 08:11 modules -> /usr/lib/nginx/modules
-rw-r--r-- 1 root root 648 Jul 6 08:11 nginx.conf
-rw-r--r-- 1 root root 636 Jul 6 07:59 scgi_params
-rw-r--r-- 1 root root 664 Jul 6 07:59 uwsgi_params
#查看对应挂载文件夹下的内容

具名挂载实例: nginx
[root@www ~]# docker run -d -P --name nginx03 -v nginx:/etc/nginx nginx
a5b2a5e9f46c648cb4e18e16ac9442e513102b9d67481c76aaf6057ff0fc5950
[root@www ~]# docker volume ls
DRIVER VOLUME NAME
local 67893edc86b502ec91342bed2dff23f1ea01f67bc368a42e250ea37dc7e9c56a
local b004ad49f0207dfbbeca19fc428b7087f40af488bcf62b5c627c4bca087fdf06
local fc7d739c835251dc6a0994c4b5f25e5087524b6565d0b19989835c889d06ec4d
local nginx
[root@www ~]# docker volume inspect nginx
[
{
"CreatedAt": "2021-08-04T00:50:57-07:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/nginx/_data",
"Name": "nginx",
"Options": null,
"Scope": "local"
}
]
[root@www ~]# ls /var/lib/docker/volumes/nginx/_data
conf.d fastcgi_params mime.types modules nginx.conf scgi_params uwsgi_params

容器读写权限:
通过 -v 容器内路径:ro(rw) 改变读写权限
ro readonly,rw readwrite

docker run -d -P --name nginx04 -v nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx04 -v nginx:/etc/nginx:rw nginx
#只要看ro就说明这个路径只能通过宿主机进行写操作,容器内是只读的。

dockerfile

dockerfile是用来构建镜像的文件,如果想要构建自己的镜像文件,就可以使用dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
构建步骤:
1.编写一个dockerfile文件
2.docker build构建称为一个镜像
3.docker run 运行镜像
4.docker push 发布镜像
基础知识∶
1、每个保留关键字(指令)都是必须是大写字母
2、执行从上到下顺序执行
3、#表示注释
4、每一个指令都会创建提交一个新的镜像层,并提交!

dockerfile:构建文件,定义了一切的步骤,源代码
dockerimages:dockerfile构建生成的镜像,最终发布和运行的产品
docker容器:容器就是镜像运行起来提供服务器

FROM #指定基础镜像,一切从from开始构建
MAINTAINER #指定镜像负责人信息。镜像是谁写的,姓名+邮箱
RUN #镜像构建的时候需要运行的命令
ADD #copy文件,会自动解压
WORKDIR #镜像的工作目录
VOLUME #容器挂载目录
EXPOSE #指定对外的端口
CMD #指定容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT #指定容器启动的时候要运行的命令,可以追加命令
ONBUILD #当构建一个被集成 dockerfile 这个时候就会运行ONBUILD 的指令。触发指令。
COPY # 类似ADD,将文件拷贝到镜像中。
ENV # 构建的时候设置环境变量。

实战测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Docker Hub中99%镜像都是从这个基础镜像过来的(FROM scratch),然后配置需要的软件和配置来进行的构建
测试dockerfile:
dockerfile:(vim dockerfile)
FROM centos
MAINTAINER ysw<1072023998@qq.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

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


EXPOSE 80

CMD echo $MYPATH
CMD echo "构建完毕"
CMD /bin/bash

docker build -f ./dockerfile -t mycentos:0.1 .
~ 进去以后所在目录为/usr/local,也就是设置好的工作目录,初始拥有vim和ifconfig功能。

基础镜像:

基础镜像就是dockerfile中的最底层镜像,例如我想自己写一个自制的tomcat容器,我就可以使用官方中已有的jdk镜像作为基础镜像,然后再在上面传入tomcat。

scratch

提到基础镜像就得说scratch。scratch是所有镜像中最小的镜像,是直接和宿主机共享内核的镜像,是一个空镜像,其镜像

既然scratch不能被拉取,如何做到docker image ls看到一个0字节的镜像

官方给出了下面方法:

1
2
3
4
Copy$ tar cv --files-from /dev/null | docker import - scratch
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
scratch latest 775bfce21429 9 minutes ago 0B

在dockerfile中使用from scratch就可以使用该镜像,但生产环境一般不使用该镜像,该镜像优点是构建出来的镜像小,环境最干净,但如果对镜像大小无要求,还是通过centos或者jdk之类的镜像作为底层镜像构建起来更方便。

CMD 和ENTRYPOINT 区别:

cmd和entrypoint都是指容器在run的时候要运行的参数命令,cmd是替换原本的参数,entrypoint则是追加参数。

cmd:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
		#编写dockerfile 文件
[root@kuangshen dockerfile]# vim dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]
#构件镜像
[root@kuangshen dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .
# run运行,发现我们的1s -a命令生效
[root@kuangshen dockerfile]# docker run dd8e4401d72f
.
..
.dockerenv
bin
dev
etc
home
lib
1ib64

#想追加一个命令 -l ls -al
[root@kuangshen dockerfile]# docker run dd8e4401d72f -1
docker: Error response from daemon: OCI runtime create failed: container_ _linux. go:349: starting
cmd并非追加,而是替换,其命令从原本的ls -a 变成-l.所以这里把参数换成其他命令试试
[root@master1 dockfile]# docker run --rm cmdtest hostname
dc49513f2fec
或者重新写一遍ls -al
[root@master1 dockfile]# docker run --rm cmdtest ls -al
total 0
drwxr-xr-x 1 root root 6 Jan 22 07:58 .
drwxr-xr-x 1 root root 6 Jan 22 07:58 ..
-rwxr-xr-x 1 root root 0 Jan 22 07:58 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x 5 root root 340 Jan 22 07:58 dev
drwxr-xr-x 1 root root 66 Jan 22 07:58 etc
drwxr-xr-x 2 root root 6 Nov 3 2020 home
lrwxrwxrwx 1 root root 7 Nov 3 2020 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 2020 lib64 -> usr/lib64
drwx------ 2 root root 6 Sep 15 14:17 lost+found
drwxr-xr-x 2 root root 6 Nov 3 2020 media
drwxr-xr-x 2 root root 6 Nov 3 2020 mnt
drwxr-xr-x 2 root root 6 Nov 3 2020 opt
dr-xr-xr-x 249 root root 0 Jan 22 07:58 proc
dr-xr-x--- 2 root root 162 Sep 15 14:17 root
drwxr-xr-x 11 root root 163 Sep 15 14:17 run
lrwxrwxrwx 1 root root 8 Nov 3 2020 sbin -> usr/sbin
drwxr-xr-x 2 root root 6 Nov 3 2020 srv
dr-xr-xr-x 13 root root 0 Jan 22 07:58 sys
drwxrwxrwt 7 root root 171 Sep 15 14:17 tmp
drwxr-xr-x 12 root root 144 Sep 15 14:17 usr
drwxr-xr-x 20 root root 262 Sep 15 14:17 var
总之这里cmd是把dockerfile cmd后面的命令全部重写了

entrypoint:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
vim docker-ENTRYPOINT
from centos
ENTRYPOINT ["ls","-a"]
[root@www ~]# docker build -f docker-ENTRYPOINT -t cntrypoint_test .
Sending build context to Docker daemon 296MB
Step 1/2 : from centos
---> 300e315adb2f
Step 2/2 : ENTRYPOINT ["ls","-a"]
---> Running in c615dc306cc6
Removing intermediate container c615dc306cc6
---> 3a4a0c68d308
Successfully built 3a4a0c68d308
Successfully tagged cntrypoint_test:latest
[root@www ~]# docker run cntrypoint_test:latest
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
[root@www ~]# docker run cntrypoint_test:latest -l
total 0
drwxr-xr-x 1 root root 6 Aug 30 06:15 .
drwxr-xr-x 1 root root 6 Aug 30 06:15 ..
-rwxr-xr-x 1 root root 0 Aug 30 06:15 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x 5 root root 340 Aug 30 06:15 dev
drwxr-xr-x 1 root root 66 Aug 30 06:15 etc
drwxr-xr-x 2 root root 6 Nov 3 2020 home
lrwxrwxrwx 1 root root 7 Nov 3 2020 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 2020 lib64 -> usr/lib64
drwx------ 2 root root 6 Dec 4 2020 lost+found
drwxr-xr-x 2 root root 6 Nov 3 2020 media
drwxr-xr-x 2 root root 6 Nov 3 2020 mnt
drwxr-xr-x 2 root root 6 Nov 3 2020 opt
dr-xr-xr-x 186 root root 0 Aug 30 06:15 proc
dr-xr-x--- 2 root root 162 Dec 4 2020 root
drwxr-xr-x 11 root root 163 Dec 4 2020 run
lrwxrwxrwx 1 root root 8 Nov 3 2020 sbin -> usr/sbin
drwxr-xr-x 2 root root 6 Nov 3 2020 srv
dr-xr-xr-x 13 root root 0 Aug 30 06:15 sys
drwxrwxrwt 7 root root 145 Dec 4 2020 tmp
drwxr-xr-x 12 root root 144 Dec 4 2020 usr
drwxr-xr-x 20 root root 262 Dec 4 2020 var

entrypoint这里是在命令后面添加参数而非替换,所以这里是ls -al

tomcat实战:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
1.准备镜像文件,tomcat压缩包,jdk压缩包
2.编写dockerfile文件

[root@www ~]# mkdir docker-tomcat
上传jdk和tomcat
[root@www docker-tomcat]# ls
apache-tomcat-10.0.10.tar.gz jdk-8u162-linux-x64.tar.gz
[root@www docker-tomcat]#echo "这是我的tomcat" >readme.txt
[root@www docker-tomcat]# vim dockerfile
FROM centos
MAINTAINER ysw<1072023998@qq.com>

COPY readme.txt /usr/local/readme.txt

ADD jdk-8u162-linux-x64.tar.gz /usr/local
ADD apache-tomcat-10.0.10.tar.gz /usr/local

RUN yum -y install vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_162
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-10.0.10
ENV CATALINA_BASE /usr/local/apache-tomcat-10.0.10
ENV PATH $PATH:$JAVA_HOME/bin:CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-10.0.10/bin/startup.sh && tail -f /usr/local/apache-tomcat-10.0.10/logs/catalina.out
3.启动镜像并测试
[root@www docker-tomcat]# docker builjavad -f dockerfile -t mytomcat .
[root@www docker-tomcat]# docker run -d -p9090:8080 --name mytomcat -v /home/tomcat/webapps:/usr/local/apache-tomcat-10.0.10/webapps -v /home/tomcat/logs:/usr/local/apache-tomcat-10.0.10/logs mytomcat
[root@www docker-tomcat]# curl localhost:9090 #访问测试一下
此时/home/tomcat/webapps和logs也应该是同步了数据的。

如果想简化可以直接将基础镜像换成jdk。

dockerhub发布

1.https://hub.docker.com/ 注册账号
2.在本地docker上登录上hub
3.在服务器上提交自己的镜像
#这个不太重要,一般生产环境还是用harbor,主要需要知道怎么打标签和推拉镜像

    [root@www ~]# docker login -u qq1072023998
        Password: 
        WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
        Configure a credential helper to remove this warning. See
        https://docs.docker.com/engine/reference/commandline/login/#credentials-store

        Login Succeeded
        [root@www ~]# docker push mytomcat
        Using default tag: latest
        The push refers to repository [docker.io/library/mytomcat]
        811b44491cc1: Preparing 
        c0450aa778e7: Preparing 
        f8d3ab6143f1: Preparing 
        d499f629a0ec: Preparing 
        2653d992f4ef: Preparing 
        denied: requested access to the resource is denied#拒绝
        [root@www ~]# docker tag 76b8a0d4aafb qq1072023998/mytomcat:1.0
        [root@www ~]# docker images
        qq1072023998/mytomcat   1.0       76b8a0d4aafb   9 days ago      678MB
        需要通过tag给镜像打上标签,在标签上注明dockerhub账号,才能上传镜像
        [root@www ~]# docker push qq1072023998/mytomcat:1.0
        The push refers to repository [docker.io/qq1072023998/mytomcat]
        811b44491cc1: Pushed 
        c0450aa778e7: Pushed 
        f8d3ab6143f1: Pushed 
        d499f629a0ec: Pushed 
        2653d992f4ef: Pushed 
        1.0: digest: sha256:47996ff2ee9ffa96a3722b22440b52600ecf70028bac52c5c6e308f2e24604fc size: 1373

DOCKER 网络

1
2
3
4
5
1、我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0桥接模式,使用的技术是evth-pair技术!
#我们发现这个容器带来网卡,都是―对对的
# evth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一段连着协议,一段彼此相连# 正因为有这个特性,evth-pair充当一个桥粱,连接各种虚拟网络设备的
# Openstac,Docker容器之间的连接,ovs的连接,都是使用evth-pair技术
所有的容器在不指定网络的情况下,都是通过docker0来进行路由的,dokcer会给容器分配一个默认的可用ip。

docker解决容器间使用容器名进行访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
--link 容器名字,容器生成时加入该参数,但如果要连接的容器不存在则会保存。相当于把link指定的容器名加入到/etc/hosts
测试:
tty1:
[root@www ~]# docker run -it -P --name centos centos
[root@bcb5179df475 /]#
tty2:
[root@www ~]# docker run -it -P --name centos_1 --link centos centos
[root@392cded8ab68 /]# ping centos
PING centos (172.17.0.3) 56(84) bytes of data.
64 bytes from centos (172.17.0.3): icmp_seq=1 ttl=64 time=0.169 ms
64 bytes from centos (172.17.0.3): icmp_seq=2 ttl=64 time=0.051 ms
^C
--- centos ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 4ms
rtt min/avg/max/mdev = 0.051/0.110/0.169/0.059 ms

这里因为centos不能后台运行(没有主进程后台运行会自动杀掉进程),所以两个都以前台方式进行运行。

自定义网络:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   docker network:
可以查看网络情况
docker network ls 可以查看有哪些网络
docker inspect 容器网络id名 查看网络id的具体信息

docker network ls :
网络模式:
bridge 桥接模式 默认
none 不配置网络
host 和宿主机共享网络
container 容器网络连接(用得少,局限性很大)
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
create 创建网络
--driver 网络类型
--subnet 子网范围
--gateway网关
mynet 网络名称
自建的网络和docker0不同,自建的网络在所有容器中均为互通,例如这里我用前面创建的容器ping网关
[root@392cded8ab68 /]# ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=0.206 ms
64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=0.048 ms
64 bytes from 192.168.0.1: icmp_seq=3 ttl=64 time=0.049 ms

网络连通:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
这里的网络连通是指把容器和某个docker网卡(创建的)连接在一起,下面的例子因为使用的是上面自定义网络创建的bridge网关,所以即使不连通也可以正常通信。
docker network connect [OPTIONS] NETWORK CONTAINER
Options:
--alias strings Add network-scoped alias for the container
--driver-opt strings driver options for the network
--ip string IPv4 address (e.g., 172.30.100.104)
--ip6 string IPv6 address (e.g., 2001:db8::33)
--link list Add link to another container
--link-local-ip strings Add a link-local address for the container
例子:
docker inspect 392c(容器id)
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "f9dafedc16fba5463666618adcd1902c5906ce802bb2dc2dbeb4f47246a2a6a8",
"EndpointID": "b713a8f139267fff066e65f8ee4db9e4d773cece9fa38f6743b687352df392dd",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.4",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:04",
"DriverOpts": null
}
#上图为截取的网络信息
[root@www ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
f9dafedc16fb bridge bridge local
229eb5b18087 host host local
8b0e339d48d4 mynet bridge local
11ee0dac2134 none null local
可以看到,其网络属于第一个网络

[root@www ~]# docker network connect 8b0e339d48d4 392cd
[root@www ~]# docker inspect 392c
这里加入网络连通以后再查看容器信息(网络信息)
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "f9dafedc16fba5463666618adcd1902c5906ce802bb2dc2dbeb4f47246a2a6a8",
"EndpointID": "b713a8f139267fff066e65f8ee4db9e4d773cece9fa38f6743b687352df392dd",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.4",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:04",
"DriverOpts": null
},
"mynet": {
"IPAMConfig": {},
"Links": null,
"Aliases": [
"392cded8ab68"
],
"NetworkID": "8b0e339d48d4266980d45dd72739a5a3e7d2eadd819cd6d689892f09950d09af",
"EndpointID": "857c352caf90da71c07cc21fc7e849a96be1ad3eeb5b2164712f411fbc8a3338",
"Gateway": "192.168.0.1",
"IPAddress": "192.168.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:c0:a8:00:02",
"DriverOpts": {}
}
可以看到这里多了一个网络(网卡)
再在容器里面查看
[root@392cded8ab68 /]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
24: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
27: eth1@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c0:a8:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.0.2/16 brd 192.168.255.255 scope global eth1
valid_lft forever preferred_lft forever
容器里面也多了一张网卡,由此可见
docker network connect 本身是将某张网卡加入到某个容器,以此来实现容器间(网卡之间)网络连通的问题。

实战

redis集群:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[root@www ~]# docker network create redis --subnet 172.38.0.0/16
for port in $(seq 1 6); do mkdir -p /mydata/redis/node-${port}/conf; touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF > /mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done;



#上面的脚本为生成6个redis配置文件已经文件夹,用于映射到6个redis里面
#!/bin/bash
for port in $(seq 1 6);
do docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} -v /mydata/redis/node-${port}/data:/data -v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf ;done

#上面的脚本为创建6个redisdocker镜像并启动

docker exec -it redis-1 /bin/sh
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
#配置集群