当前位置: 首页 > 科技观察

终于有人把Docker解释清楚了!

时间:2023-03-17 18:59:48 科技观察

在丰富的网络时代,应用程序变得越来越强大,同时也越来越复杂。集群部署、环境隔离、灰度发布、动态扩展缺一不可,容器化成为这中间必不可少的桥梁。图片来自Pexels在本文中,让我们一起探索Docker的神秘世界,从零到一掌握Docker的基本原理和实战操作。别守着前端的一亩三分地了,该开疆拓土了。讲一个故事为了更好的理解Docker是什么,先讲一个故事:我要盖房子,于是我搬石头、砍柴、画图纸、盖房子。经过一番手术,房子终于盖好了。结果住了一段时间,心血来潮就决定搬到海边去了。这时候,按照以前的办法,只能去海边,搬石头,砍柴,画图纸,重新盖房子。正在我苦恼的时候,一位魔术师来教我一种魔术。这种魔法可以把我盖的房子复制一份,做成“镜像”,放在我的背包里。到了海边,我就用这个“镜像”复制一个房子,拎着包搬进去住。是不是很神奇?对应我们的项目,房子就是项目本身,镜像就是项目的副本,背包就是镜像仓库。如果想动态扩容,就从仓库中取出项目镜像,随便复制过来。一次构建,随处运行!无需关注版本、兼容性、部署等问题,彻底解决“上线即崩溃,构建无休止”的尴尬。在启动虚拟机和容器之前,我们先准备一些基础知识:①虚拟机:虚拟化硬件虚拟机虚拟机是指通过软件模拟出具有完整硬件系统功能,运行在完全隔离的环境中的完整计算机系统。在物理计算机上可以完成的所有事情都可以在虚拟机上完成。在计算机上创建虚拟机时,需要使用物理机的部分硬盘和内存容量作为虚拟机的硬盘和内存容量。每个虚拟机都有独立的CMOS、硬盘和操作系统,可以像物理机一样操作虚拟机。在容器技术出现之前,业界的网红就是虚拟机。虚拟机技术的代表是VMWare和OpenStack。②容器:将操作系统层虚拟化,是一个标准的软件单元。其特点如下:Runanywhere:容器可以将代码、配置文件和相关依赖库打包,保证在任何环境下运行一致。资源利用率高:容器提供进程级别的隔离,可以更精细地设置CPU和内存使用率,从而更好地利用服务器计算资源。快速伸缩:每个容器都可以作为一个单独的进程运行,可以共享底层操作系统的系统资源,可以加快容器的启停效率。区别与联系:一个虚拟机虽然可以隔离出很多“子机”,但占用空间大,启动速度慢。虚拟机软件也可能要花钱,比如VMWare。容器技术不需要虚拟化整个操作系统,只需要虚拟化一个小规模的环境,类似于“沙盒”。在运行空间方面,虚拟机一般需要几GB到几十GB的空间,而容器只需要MB甚至KB。我们来看一下对比数据:虚拟机属于虚拟化技术,而Docker等容器技术属于轻量级虚拟化。容器比虚拟机更轻、更快,因为它们利用底层Linux操作系统在隔离环境中运行。虚拟机的管理程序创建了一个非常强大的边界以防止应用程序破坏它,而容器的边界则没有那么强大。认识DockerDocker是一个开源应用程序容器引擎,它允许开发人员将他们的应用程序和依赖项打包到一个可移植的容器中,然后将其发布到任何流行的Linux机器上,它还可以被虚拟化。容器完全使用沙箱机制,它们之间不会有任何接口。Docker技术的三个核心概念是:ImageImageContainerContainerWarehouseRepositoryDocker轻量级的原因是什么?相信大家也会有这样的疑惑:Docker为什么启动快?如何与主机共享内核?当我们要求Docker运行一个容器时,Docker会在你的计算机上设置一个资源隔离的环境。然后将打包后的应用程序和相关文件复制到Namespace内的文件系统中,环境配置完成。然后Docker将执行我们预先指定的命令来运行应用程序。镜像不包含任何动态数据,构建后内容不会改变。核心概念核心概念如下:Build,ShipandRun(建造、运输、运行)。Buildonce,Runanywhere(构建一次,到处运行)。Docker本身并不是容器,它是一个创建容器的工具,是一个应用容器引擎。Docker的三个核心概念是:MirrorImage、Container、Repository。Docker技术使用Linux内核和内核特性(例如Cgroups和命名空间)来分隔进程,以便每个进程独立于其他进程运行。由于Namespace和Cgroups功能仅在Linux上可用,因此容器无法在其他操作系统上运行。那么Docker如何在macOS或Windows上工作?Docker其实用了一个trick,在非Linux操作系统上安装一个Linux虚拟机,然后在虚拟机内部运行容器。镜像是一个可执行包,其中包含运行应用程序所需的代码、运行时、库、环境变量和配置文件,容器是镜像的运行时实例。更多关于Docker的原理可以查看《Docker 工作原理及容器化简易指南》,这里不再赘述:http://dockone.io/article/8788安装Docker①在命令行安装Homebrew的Cask已经支持DockerMac,所以可以很方便的使用HomebrewCask安装,执行以下命令:brewcaskinstalldocker更多安装方法请查看官方文档:https://www.docker.com/get-started②查看版本命令如下:docker-v③配置镜像加速设置DockerEngine写入配置:{"registry-mirrors":["http://hub-mirror.c.163.com/","https://registry.docker-cn.com"],"insecure-registries":[],"experimental":false,"debug":true}④安装桌面终端桌面终端的操作很简单,先去官网下载[1].通过Docker桌面,我们可以很方便的操作:克隆:克隆一个项目。build:打包镜像。运行:运行实例。分享:分享图片。好了,准备就绪,可以大显身手了!快速入门安装好Docker之后,我们来创建一个实际项目的镜像,边用边学。①首先,我们需要对下图将要用到的11条命令有个大概的了解:②为了快速新建一个项目,我们直接使用Vue脚手架搭建项目:vuecreatedocker-demo尝试启动一下:yarnserve访问地址:http://localhost:8080/。项目准备好了,接下来我们对项目进行打包:yarnbuild此时项目目录下的Dist就是我们要部署的静态资源,继续下一步。注意:前端项目一般分为两类,一类是直接通过Nginx静态部署,一类需要启动Node服务。本节我们只考虑第一个。关于Node服务,后面会详细讲解。③新的Dockerfile命令如下:cddocker-demo&&touchDockerfile此时的项目目录如下:.├──Dockerfile├──README.md├──babel.config.js├──dist├──node_modules├───package.json├──public├──src└──yarn.lock可以看到我们在docker-demo目录下成功创建了Dockerfile。④准备Nginx镜像运行你的Docker桌面端,就会默认启动实例,我们在控制台拉取Nginx镜像:dockerpullnginx控制台会出现如下信息:Usingdefaulttag:latestlatest:Pullingfromlibrary/nginx8559a31e96f4:Pullcomplete8d69e59170f7:Pullcomplete3f9f1ec1d262:Pullcompleted1f5ff4f210d:Pullcomplete1e22bfa8652e:PullcompleteDigest:sha256:21f32f6c08406306d822a0e6e8b7dc81f53f336570e852e25fbe1e3e3d0d0133Status:Downloadednewerimagefornginx:latestdocker.io/library/nginx:latest如果出现此类异常,请确认Docker实例是否正常运行。无法连接到Docker守护进程tunix:///var/run/docker.sock。docker守护进程是否正在运行?镜像准备好了,我们在根目录下创建Nginx配置文件:touchdefault.conf写:server{listen80;server_namelocalhost;#charsetkoi8-r;access_log/var/log/nginx/host.access.logmain;error_log/var/log/nginx/error.logerror;location/{root/usr/share/nginx/html;indexindex.htmlindex.htm;}error_page500502503504/50x.html;location=/50x.html{root/usr/share/nginx/html;}}⑤配置镜像打开Dockerfile,写入如下内容:FROMnginxCOPYdist//usr/share/nginx/html/COPYdefault.conf/etc/nginx/conf.d/default.conf下面一行一行解释代码:FROMnginx指定该镜像是基于nginx:latest镜像构建的。COPYdist//usr/share/nginx/html/命令的意思是将项目根目录下dist文件夹下的所有文件复制到镜像中的/usr/share/nginx/html/目录下。COPYdefault.conf/etc/nginx/conf.d/default.conf将default.conf复制到etc/nginx/conf.d/default.conf,将Nginx镜像中的default配置替换为本地的default.conf配置。⑥构建镜像Docker通过构建命令构建镜像:dockerbuild-tjartto-docker-demo。按照惯例,我们来解释一下上面的代码:-t参数给镜像命名为jartto-docker-demo。.是基于当前目录下的Dockerfile构建镜像。执行成功后会输出:SendingbuildcontexttoDockerdaemon115.4MBStep1/3:FROMnginx--->2622e6cca7ebStep2/3:COPYdist//usr/share/nginx/html/--->Usingcache--->82b31f98dce6Step3/3:COPYdefault.conf/etc/nginx/conf.d/default.conf--->7df6efaf9592成功构建7df6efaf9592成功标记jartto-docker-demo:latest镜像创建成功!我们查看一下容器:dockerimagels|grepjartto-docker-demo可以看到我们创建了一个133MB的Project镜像:jartto-docker-demolatest7df6efaf9592关于minuteago133MB的镜像也有好有坏,后面会介绍如何优化,可以暂时此处忽略。⑦运行容器的命令如下:dockerrun-d-p3000:80--namedocker-vuejartto-docker-demo此处解释参数:-d设置容器后台运行。-p表示端口映射,将机器的3000端口映射到容器的80端口(这样外网就可以通过机器的3000端口访问了。--name设置容器名称docker-vue.jartto-docker-demo是我们上面构建的镜像的名称。再补充一点:在控制台中,我们可以通过dockerps查看新运行的Container的ID:dockerps-a控制台会输出:CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMESab1375befb0bjartto-docker-demo"/docker-entrypoint.…"8minutesagoUp7minutes0.0.0.0:3000->80/tcpdocker-vue如果你用的是桌面,那么打开DockerDashboard可以看到容器列表,如下图:⑧访问项目因为我们映射的是本地3000端口,所以执行:curl-v-ilocalhost:3000或打开浏览器,访问:localhost:3000。⑨发布镜像如果你想为社区做贡献,需要发布镜像供其他开发者使用。发布镜像需要以下步骤:登录dockerhub[2]并注册一个账号。在命令行执行dockerlogin,然后输入我们的账号密码进行登录,在推送镜像之前,需要打tag,执行dockertag/:。整个过程就结束了,我们以后要用到,再也不用“搬石头、砍柴、画图纸、盖房子”,拎着包搬进去了。这也是Docker的独特魅力。常规操作就到这里。恭喜你完成了Docker入门项目!如果想更深入,不妨继续往下看。①参数使用FROM:指定基础镜像,所有构建的镜像都必须有一个基础镜像,FROM命令必须是Dockerfile的第一个命令FROM[AS]指定从一个镜像构建的新镜像的名称FROM[:][AS]指定镜像的版本Tag示例:FROMmysql:5.0ASdatabaseMAINTAINER:镜像维护者信息MAINTAINER示例:MAINTAINERJarttoJartto@qq.comRUN:构建镜像时要执行的命令RUN示例:RUN["executable","param1","param2"]ADD:将本地文件添加复制到容器中,压缩包解压,网络上的文件可以访问,ADD将自动下载示例:ADD*.js/app将js文件添加到容器中的app目录下COPY:功能同ADD,只是复制,不解压或下载文件CMD:启动容器后执行的命令,与RUN不同,是buildtheimage要运行的命令当使用dockerrun运行容器时,这个可以在命令行中覆盖例如:CMD["executable","param1","param2"]ENTRYPOINT:也是一个执行命令,和CMD一样,但是这个命令不会被命令行覆盖键值格式LABEL==...示例:LABELversion="1.0"description="Thisisawebapplication"ENV:设置环境变量,有些容器在运行时会需要一些环境变量ENV设置一个环境变量ENV===设置多个环境变量示例:ENVJAVA_HOME/usr/java1.8/EXPOSE:对外暴露的端口(容器内部程序的端口,虽然会和宿主机的一样,但实际上是两个端口)EXPOSE示例:EXPOSE80容器运行时,需要使用-p映射外部端口才能访问容器VOLUME中的端口:指定数据持久化的目录,官方语言叫mountVOLUME/var/log指定容器中需要挂载的目录,并将该目录映射到宿主机上的随机目录,实现数据持久化和同步VOLUME["/var/log","/var/test".....]co中指定多个目录ntainer,将这些目录映射到宿主机上的多个随机目录,实现数据持久化和同步VOLUME/var/datavar/log指定容器将宿主机中的var/log目录挂载到/var/主机上的数据目录。在这种形式下,您可以手动指定主机上的目录WORKDIR:设置工作目录。设置完成后,RUN、CMD、COPY、ADD的工作目录都会同步变化WORKDIR例子:WORKDIR/app/testUSER:指定运行命令的用户。为了安全和权限,根据要执行的命令选择不同的用户USER:[]示例:USERtestARG:设置构建镜像时要传递的参数ARG[=]ARGname=sss更多操作请移步官方文档[3]:https://docs.docker.com/最佳实践掌握了Docker的常规操作后,我们就可以轻松创建自己想要的项目镜像了。但是,不同的操作产生的图像也有很大的不同。究竟是什么造成了镜像差异,我们不妨继续探索。以下是应用Docker过程中的最佳实践。请尽量遵循以下准则:要求明确:需要什么图像。步骤简化:优先考虑变化少的步骤。清晰版:图像命名清晰。Documentation:可以复现整个镜像打包步骤。结语容器化技术必将成为云时代不可或缺的技能之一,而Docker只是沧海一粟。然后是集群容器管理Kubernetes、ServiceMesh、Istio等技术。打开Docker的大门,继续抽丝剥茧,层层深入,你会感受到容器化的无穷魅力。相关链接:https://www.docker.com/products/docker-desktophttps://hub.docker.com/https://docs.docker.com/作者:jartto编辑:陶家龙来源:http:///jartto.wang/2020/07/04/learn-docker/