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)
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)
其工作流程大致为,当用户需要启动一个镜像时,用户从客户端发送命令(通过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
访问:ip+port(9000),第一次登陆设置用户名密码
(就是一个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 #配置集群