在Linux(Ubuntu)中安装dockeraptgetremovedockerdockerenginedocker。iocontainerdruncaptupdateaptgetinstallcacertificatescurlgnupglsbreleasecurlfsSLhttp:mirrors。aliyun。comdockercelinuxubuntugpgsudoaptkeyaddaddaptrepositorydeb〔archamd64〕http:mirrors。aliyun。comdockercelinuxubuntu(lsbreleasecs)stableaptgetinstalldockercedockerceclicontainerd。io中途出现问题的话,使用sudoaptgetupdate试试systemctlstartdockeraptgetyinstallapttransporthttpscacertificatescurlsoftwarepropertiescommonservicedockerrestartdockerrunhelloworlddockerversiondocker常用命令帮助命令dockerversion显示Docker版本信息dockerinfo显示Docker系统信息,包括镜像和容器数量dockerhelp帮助文档镜像命令dockerimages〔options〕列出本地主机上的镜像optionsa:列出本地所有镜像q:只显示镜像iddockersearch〔imagename〕〔options〕dockersearch某个镜像的名称(对应DockerHub仓库中的镜像)optionsfilterstars50列出收藏数不小于指定值的镜像dockerpull〔imagename〕:〔tag〕下载镜像dockerimagermf〔imagenameorimageid〕。。。删除一个或多个镜像dockerimagermf(dockerimagesaq)删除本地全部镜像dockerimageinspect〔imageid〕查看镜像元数据dockerhistory〔imageidorimagename〕列出镜像的变更历史dockerloginu〔username〕登录dockerhubdockerpushchrishimycentos:1。0将镜像发布出去容器命令dockerrun〔options〕image〔command〕optionsnameName给容器指定一个名字d后台方式运行容器,并返回容器的idi以交互模式运行容器,通常和t一起使用t给容器重新分配一个终端,通常和i一起使用P随机端口映射(大写)p指定端口映射(小写),一般可以有四种写法ip:hostPort:containerPortip::containerPorthostPort:containerPort(常用)containerPortdockerrunitcentosbinbash使用centos用交互模式启动容器,在容器内执行binbash命令使用exit退出容器dockerps〔options〕列出所有运行的容器optionsa列出当前所有正在运行的容器历史运行过的容器l显示最近创建的容器n?显示最近n个创建的容器q只显示容器编号exit容器停止退出ctrlPQ容器不停止退出dockerstart〔containeridorcontainername〕启动容器dockerrestart〔containeridorcontainername〕重启容器dockerstop〔containeridorcontainername〕停止容器dockerkill〔containeridorcontainername〕强制停止容器dockerrm〔containerid〕删除指定容器dockerrmf(dockerpsaq)删除所有容器dockerpsaqxargsdockerrm删除所有容器dockerlogs〔options〕〔containerid〕查看容器日志optionst显示时间戳f打印最新的日志(followlogoutput)tail数字显示多少条dockertop〔containerid〕查看容器中运行的进程信息dockerinspect〔containerid〕查看容器的元数据dockerexecit〔containerid〕〔bashshell〕进入正在运行的容器(是在容器中打开新的终端,并且可以启动新的进程)dockerattach〔containerid〕直接进入容器启动命令的终端,不会启动新的进程dockercp容器id:容器内路径目的主机路径从容器内拷贝文件到主机上dockercommitm提交的描述信息a作者容器id要创建的目标镜像名:〔标签名〕从容器创建一个新的镜像容器数据卷挂载方式一:容器中直接使用命令来挂载dockerrunitv宿主机绝对路径目录:容器内目录镜像名binbashegdockerrundp3310:3306vhomemysqlconf:etcmysqlconf。dvhomemysqldata:varlibmysqleMYSQLROOTPASSWORD123456namemysql01mysql:5。7挂载方式二:通过DockerFile来挂载DockerfileFROMcentosVOLUME〔dataVolumeContainer1,dataVolumeContainer2〕CMDechoendCMDbinbashdockerbuildtchrisshicentos。匿名和具名挂载匿名挂载v容器内路径dockerrundPnamenginx01vetcnginxnginx匿名挂载的缺点,就是不好维护,通常使用命令dockervolume维护dockervolumels具名挂载v卷名:容器内路径dockerrundPnamenginx02vnginxconfig:etcnginxnginxdockervolumeinspectnginxconfig查看挂载的路径怎么判断挂载的是卷名而不是本机目录名?不是开始就是卷名,是开始就是目录名Dockerfile基础知识每条保留字指令都必须为大写字母且后面要跟随至少一个参数指令按照从上到下,顺序执行表示注释每条指令都会创建一个新的镜像层,并对镜像进行提交构建步骤编写Dockerfile文件dockerbuild构建镜像dockerrun构建过程docker从基础镜像运行一个容器执行一条指令并对容器做出修改执行类似dockercommit的操作提交一个新的镜像层docker再基于刚刚提交的镜像运行一个新容器执行Dockerfile中的下一条指令直到所有指令都执行完成Dockerfile指令FROM基础镜像,当前新镜像是基于哪个镜像的MAINTAINER镜像维护者的姓名混合邮箱地址RUNdockerbuild时需要运行的命令EXPOSE当前容器对外保留出的端口WORKDIR指定在创建容器后,终端默认登录的进来工作目录,一个落脚点ARGdockerbuild时Dockerfile文件中的变量ENVdockerrun时设置环境变量COPY拷贝文件和目录到镜像中ADD功能与COPY一样,但是多了自动解压文件的功能VOLUME容器数据卷,用于数据保存和持久化工作CMDdockerrun时要运行的命令,Dockerfile中可以有多个CMD指令,但只有最后一个生效ENTRYPOINTdockerrun时要运行的命令,和CMD一样ONBUILD当构建一个被继承的Dockerfile时运行命令,父镜像在被子镜像继承后,父镜像的ONBUILD被触发 CMD:Dockerfifile中可以有多个CMD指令,但只有最后一个生效,CMD会被dockerrun之后的参数替换! ENTRYPOINT:dockerrun之后的参数会被当做参数传递给ENTRYPOINT,之后形成新的命令组合!实例 背景:官方默认的centos镜像默认路径是,默认不支持vim,默认不支持ifcofig 目的:使我们自己的镜像具备如下:登录后的默认路径(usrlocal)、vim编辑器、查看网络配置ifconfig支持DockerfileFROMcentos:7MAINTAINERchris。shisxy0129yeah。netENVMYPATHusrlocalWORKDIRMYPATHRUNyumupdateRUNyumyinstallvimRUNyumyinstallnettoolsEXPOSE80CMDechoMYPATHCMDechoendCMDbinbash构建dockerbuildt新镜像名字:TAG。dockerbuildtmycentos:1。0。运行dockerrunit新镜像名字:TAGdockerrunitmycentos:1。0列出镜像的变更历史dockerhistory〔imageid〕docker网络讲解理解docker0原理每一个安装了docker的linux主机都有一个docker0的虚拟网卡。这个是桥接网卡,使用了vethpair技术rootchrisvirtualmachine:ipaddr1:lo:LOOPBACK,UP,LOWERUPmtu65536qdiscnoqueuestateUNKNOWNgroupdefaultqlen1000linkloopback00:00:00:00:00:00brd00:00:00:00:00:00inet127。0。0。18scopehostlovalidlftforeverpreferredlftforeverinet6::1128scopehostvalidlftforeverpreferredlftforever2:ens33:BROADCAST,MULTICAST,UP,LOWERUPmtu1500qdiscfqcodelstateUPgroupdefaultqlen1000linkether00:0c:29:7a:47:5abrdff:ff:ff:ff:ff:ffaltnameenp2s1inet192。168。32。12824brd192。168。32。255scopeglobaldynamicnoprefixrouteens33validlft5529035secpreferredlft5529035secinet6fe80::7a87:6135:1c98:61a964scopelinknoprefixroutevalidlftforeverpreferredlftforever3:docker0:NOCARRIER,BROADCAST,MULTICAST,UPmtu1500qdiscnoqueuestateDOWNgroupdefaultlinkether02:42:8c:f2:d0:2dbrdff:ff:ff:ff:ff:ffinet172。17。0。116brd172。17。255。255scopeglobaldocker0validlftforeverpreferredlftforeverinet6fe80::42:8cff:fef2:d02d64scopelinkvalidlftforeverpreferredlftforever4:br89830bc6a152:NOCARRIER,BROADCAST,MULTICAST,UPmtu1500qdiscnoqueuestateDOWNgroupdefaultlinkether02:42:78:e0:07:c8brdff:ff:ff:ff:ff:ffinet192。168。0。116brd192。168。255。255scopeglobalbr89830bc6a152validlftforeverpreferredlftforever每启动一个docker容器,linux主机就会多一个虚拟网卡我们启动了一个tomcat01(172。17。0。2),主机的ip地址多了一个24:vethf840e91if23dockerrundPnametomcat01tomcat然后我们在tomcat01容器中查看容器的ip是23:eth0if24dockerexecittomcat01ipaddr我们再启动一个tomcat02(172。17。03)观察dockerrundPnametomcat02tomcat然后发现linux主机上又多了一个网卡26:vethe152c3eif25我们看下tomcat02的容器内ip地址是25:eth0if26vethpair就是一对虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着。正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备!Bridge、OVS之间的连接,Docker容器之间的连接等等,以此构建出非常复杂的虚拟网络结构,比如OpenStackNeutron。测试tomcat01和tomcat02容器间是否可以互相ping通root0f3b19b75279:usrlocaltomcatping172。17。0。3PING172。17。0。3(172。17。0。3):56databytes64bytesfrom172。17。0。3:icmpseq0ttl64time2。966ms64bytesfrom172。17。0。3:icmpseq1ttl64time0。164ms64bytesfrom172。17。0。3:icmpseq2ttl64time0。171ms结论:容器和容器之间是可以互相访问的结论tomcat1和tomcat2共用一个路由器。是的,他们使用的一个,就是docker0任何一个容器启动默认都是docker0网络docker默认会给容器分配一个可用ip小结Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为ContainerIP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的ContainerIP直接通信。Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫vethpair)Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。 Link思考一个场景,我们编写一个微服务,数据库连接地址原来是使用ip的,如果ip变化就不行了,那我们能不能使用服务名访问呢? jdbc:mysql:mysql:3306,这样的话哪怕mysql重启,我们也不需要修改配置了!docker提供了link的操作!我们使用tomcat02,直接通过容器名pingtomcat01,不使用ip,发现是ping不通的我们再启动一个tomcat03,但是启动的时候连接tomcat02dockerrundPnametomcat03linktomcat02tomcat这个时候,我们就可以使用tomcat03ping通tomcat02了dockerexecittomcat03pingtomcat02再来测试,tomcat03是否可以ping通tomcat01失败再来测试,tomcat02是否可以ping通tomcat03反向也ping不通思考,这个原理是什么呢?我们进入tomcat03中查看下host配置文件rootf86e6836e0a1:usrlocaltomcatcatetchosts127。0。0。1localhost::1localhostip6localhostip6loopbackfe00::0ip6localnetff00::0ip6mcastprefixff02::1ip6allnodesff02::2ip6allrouters172。17。0。3tomcat02a263c1e773b2发现tomcat2直接被写在这里172。17。0。4f86e6836e0a1所以这里其实就是配置了一个hosts地址而已!原因:link的时候,直接把需要link的主机的域名和ip直接配置到了hosts文件中了 link早都过时了,我们不推荐使用!我们可以使用自定义网络的方式自定义网络基本概念rootchrisvirtualmachine:dockernetworkhelpUsage:dockernetworkCOMMANDManagenetworksCommands:connectConnectacontainertoanetworkcreateCreateanetworkdisconnectDisconnectacontainerfromanetworkinspectDisplaydetailedinformationononeormorenetworkslsListnetworkspruneRemoveallunusednetworksrmRemoveoneormorenetworks 所有网络模式 网络模式 配置 说明 bridge模式 netbridge 默认值,再docker网桥docker0上为容器创建新的网络栈 none模式 netnone 不配置网络,用户可以稍后进入容器,自行配置 container模式 netcontainer:nameid 容器和另外一个容器共享Networknamespace。kubernetes中的pod就是多个容器共享一个Networknamespace host模式 nethost 容器和宿主机共享Networknamespace 用户自定义 net自定义网络 用户自己使用network相关命令定义网络,创建容器的时候可以指定为自己定义的网络1。删除原来的所有容器dockerrmf(dockerpsaq)2。接下来我们来创建容器,但是我们知道默认创建的容器都是docker0网卡的dockerrundPnametomcat01netbridgetomcatdocker0网络的特点1。它是默认的2。域名访问不通3。link域名通了,但是删了又不行3。我们可以让容器创建的时候使用自定义网络dockernetworkcreatedriverbridgesubnet192。168。0。016gateway192。168。0。1mynetdockernetworklsdockernetworkinspectmynet4。我们来启动两个容器测试,使用自己的mynet!dockerrundPnametomcatnet01netmynettomcatdockerrundPnametomcatnet02netmynettomcatdockernetworkinspectmynet5。我们来测试ping容器名和ip试试,都可以ping通dockerexecittomcatnet01ping192。168。0。3dockerexecittomcatnet01pingtomcatnet02 发现,我们自定义的网络docker都已经帮我们维护好了对应的关系 所以我们平时都可以这样使用网络,不使用link效果一样,所有东西实时维护好,直接域名ping通网络联通 docker0和自定义网络肯定不通,我们使用自定义网络的好处就是网络隔离 那关键的问题来了,如何让tomcatnet01访问tomcat1?1。启动默认的容器,在docker0网络下dockerrundPnametomcat01tomcatdockerrundPnametomcat02tomcat2。我们来测试一下!打通mynetdocker0dockernetworkconnectmynettomcat01dockernetworkinspectmynet发现我们的tomcat01就进来这里了,tomcat01拥有了双ip3。tomcat01可以ping通了dockerexecittomcat01pingtomcatnet014。tomcat02依旧ping不通,大家应该就理解了 结论:如果要跨网络操作别人,就需要使用dockernetworkconnect〔OPTIONS〕NETWORKCONTAINER连接