[TOC]
网络协议
Web协议通信原理
在开始学web服务器之前,需要先理解web通信协议,才能够更好的吸收其中精华。
我们平时浏览网页的时候,会打开浏览器,输入网址后按下回车键,然后就会显示出你想要浏览的内容。在这个看似简单的用户行为背后,到底隐藏了些什么呢?
浏览器本身是一个客户端,当你输入URL的时候,首先浏览器会去请求DNS服务器,通过DNS获取相应的域名对应的IP
然后通过IP地址找到IP对应的服务器后,要求建立TCP连接
等浏览器发送完HTTP Request(请求)包后,服务器接收到请求包之后才开始处理请求包
服务器调用自身服务,返回HTTP Response(响应)包;
客户端收到来自服务器的响应后开始渲染这个Response包里的主体(body),等收到全部的内容随后断开与该服务器之间的TCP连接。
1 | 部署web服务器提供网站功能,最基本的内容展示html内容,指的是静态数据,动态数据。 |


一个Web服务器也被称为HTTP服务器,它通过HTTP协议与客户端通信。
这个客户端通常指的是Web浏览器。
web服务器工作原理
Web服务器的工作原理可以简单地归纳为:
- 客户端通过TCP/IP协议建立到服务器的TCP连接
- 客户端向服务器发送HTTP协议请求包,请求服务器里的资源文档
- 服务器向客户端发送HTTP协议应答包,如果请求的资源包含有动态语言的内容,那么服务器会调用动态语言的解释引擎负责处理”动态内容”,并将处理得到的数据返回给客户端
- 客户端与服务器断开。由客户端解释HTML文档,在客户端屏幕上渲染图形结果
客户端请求到达服务端流程
- 当客户端拿到服务端域名对应的ip后,浏览器会以一个随机端口(1024<随机端口<65535)向服务器的web程序(nginx、apache)的80端口发起tcp连接请求。
- 该请求经过复杂的网络环境后到达服务端,进入到服务器的对应的网卡,再进入到linux内核的tcplip协议栈,一层一层的解开数据包,甚至经过防火墙,最终到达nginx程序,确认tcp/ip连接。
- 确认tcp连接之后,客户端继续发起http请求,如常见的get、post请求方法。
小结
因此你会发现,web通信原理中,主要分两块协议的建立:
- tcp/ip
- HTTP

Tcp和HTTP协议
TCPIIP协议
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
简单说就是TCP协议就是控制数据包在传过过程中的规范格式。
IP是Internet Protocol(网际互连协议)的缩写,是TCP/IP体系中的网络层协议。
设计IP的目的是提高网络的可扩展性:
一是解决互联网问题,实现大规模、异构网络的互联互通;
二是分割顶层网络应用和底层网络技术之间的耦合关系,以利于两者的独立发展。
根据端到端的设计原则,IP只为主机提供一种无连接、不可靠的、尽力而为的数据包传输服务。
- TCP/IP协议指的不仅仅是tcp、和ip这两个协议。
- 而是由FTP、SMTP、TCP、UDP、IP等各种协议组成的协议簇,但是TCPIP最最具有代表性,因此俗称TCP/IP协议。


OSI七层模型


抓包分析三次握手

讲解TCP三次握手和四次握手之前,我们先了解一下TCP和UDP这两个重量级的传输层协议。
用户数据报协议UDP (User Datagram Protocol) :
- UDP在传送数据之前不需要先建立连接,远程主机在收到UDP报文后,不需要给出任何确认。
- 虽然UDP不提供可靠交付,但在某些情况下UDP确是一种最有效的工作方式(一般用于即时通信),比如: QQ语音、QQ视频、直播等等
**传输控制协议TCP **(Transmission Control Protocol) :
- TCP提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。
- TCP不提供广播或多播服务。由于TCP要提供可靠的,面向连接的传输服务(TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、流量控制、拥塞控制机制,在数据传完后,还会四次挥手断开连接用来节约系统资源),这不仅使协议数据单元的首部增大很多,还要占用许多处理机资源。
- TCP一般用于文件传输、发送和接收邮件、远程登录等场景。
抓包查看三次握手(真理)
鼎鼎大名的tcp/ip协议的三次握手、也就是关乎于syn、syn/ack、ack 三个标识位
tcp是一个及其复杂的知识点,这里咱们通过wireshare来尽量的通过实践,理解tcp的序列号和确认号的关系。
TCP协议正在报文中使用了大量的标志位来控制tcp的连接状态;
最主要的三个标志位如下
- SYN、创建一个连接
- FIN、终止一个连接
- ACK、确认接收到了数据
第一次握手(SYN)
打开tcp层的数据包信息,展开TCP的标志位区域(flag),可以看到tcp用到的所有标志位。
第二次握手(SYN、ACK)
第三次握手(ACK)
第二个数据包。第二次握手,服务端给与的ack标志位,用于确认收到客户端的SYN数据包
为什么是【SYN.ACH】?因为表明服务端也是想要建立TCP连接
图解三次握手流程
[!CAUTION]
抓包工具,查看TCP/IP的三次握手
经典问题:你了解TCP/IP的三次握手,四次挥手嘛?
具体数据包的报文格式,暂时不用过多去琢磨;
什么时候需要琢磨数据包的序列号,只有当你在生产环境下,遇见的及其棘手的问题,比如一些数据不同步,交易数据丢失等极端情况,需要去抓取数据包,逐个分析,数据包的完整性,序列号。
目前只需要大致了解数据包的类型,以及作用即可;




1 | 1、抓取ssh登录的数据包,查看 tcp/ip协议基础之上的 SSH应用层协议 |


抓包分析四次挥手
理论知识,确实重要。但得先记住理论的流程,再去动手实践,得出真知。
1 | 1、先建立ssh连接,然后退出ssh会话,查看是否发出tcp/ip的四次挥手,四个数据包。 |

TCP连接状态报文
面试时候拿出来背诵即可
1 | 1 cLOSE 没有任何连接状态 |
常用的熟知端口号
| 应用程序 | FTP | TFTP | TELNET | SMTP | DNS | HTTP | SSH | MYSQL |
|---|---|---|---|---|---|---|---|---|
| 熟知端口 | 21,20 | 69 | 23 | 25 | 53 | 80 | 22 | 3306 |
| 传输层协议 | TCP | UDP | TCP | TCP | UDP | TCP | TCP | TCP |
套接字socket学习
TCP与套接字(socket)
通过前面对OSI网络模型的学习,我们知道了在网络层中可以通过IP地址实现两个机器之间的通信。
但是这并不具体,因为真正进行通信的实体是在主机中的进程,是一个主机汇总的一个进程与另一个主机中的一个进程在交换数据。
什么是socket套接字
1 | 任何,两个机器的连接,指的是TCP/IP协议的连接,本质上是两个socket的通信 |
本地套接字
比如单机LNMP,应用程序在机器内部内存之间数据交互
1 | 套接字存在的意义,在于让两端进行数据交互,数据传输 |
网络套接字
部署LNMP,这是不同机器之间的远程访问,就是远程socket
1 | 比如http协议的交互 |
HTTP协议基础篇
这些内容都是部署网站,后续的nginx高级知识点的必备内容。
HTTP协议概述
HTTP是一个客户端终端(用户)和服务器端(网站)请求和应答的标准(TCP)。
- 通过使用网页浏览器、网络爬虫或者其它的工真,客户端发起一个HTTP请求到服务器上指定端口(默认端口为80)
- 我们称这个客户端为用户代理程序(user agent) .
- 应答的服务器上存储着一些资源,比如HTML文件和图像。我们称这个应答服务器为源服务器(origin server)。
- 在用户代理和源服务器中间可能存在多个“中间层”,比如代理服务器.网关或者隧道(tunnel)。
- 通常,由HTTP客户端发起一个请求,创建一个到服务器指定端口(默认是80端口)的TCP连接。
- HTTP服务器则在那个端口监听客户端的请求。一旦收到请求,服务器会向客户端返回一个状态,比如“HTTP/1.1 200 OK”,以及返回的内容,如请求的文件、错误消息、或者其它信息。
HTTP工作原理
HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。
HTTP协议采用了 请求/响应 模型。
客户端向服务器发送一个请求报文。请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行 作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。
HTTP请求/响应的步骤

1 | 1、客户端连接到web服务器 |
例如:在浏览器地址栏键入URL.按下回车之后会经历以下流程:
- 浏览器向DNS 服务器请求解析该URL中的域名所对应的IP地址;
- 解析出IP地址后,根据该IP地址和默认端口80。和服务器建立TCP连接;
- 浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP请求,该请求报文作为TCP三次握手的第三个报文的数据发送给服务器:
- 服务器对浏览器请求作出啊应,并把对应的html文本发送给浏览器;
- 浏览器将该 html文本并显示内容:
- 释放 TCP连接;
总结
HTTP协议是基手TCP/IP协议之上的应用层协议。
请求-响应的模式
HTTP协议规定,请求从客户端发出,最后服务器端响应该请求并返回。
换句话说,肯定是先从客户端开始建立通信的.服务器端在没有接收到请求之前不会发送响应。

无状态
HTTP是一种不保存状态,即无状态(stateless)协议。
HTTP协议自身不对请求和响应之间的通信状态进行保存。
也就是说在HTTP这个级别.协议对于发送过的请求或响应都不做持久化处理。

这种无状态设计是为了保证HTTP可以处理大量的请求响应;
http默认不会记住每一次连接的状态信息,下一次都会认为是一个新的客户端连接
1 | 比如你去找到禁用chrome浏览器的cookie功能。 |
cookie
但是如果HTTP完全无状态,你登录到淘宝网后,点击电子产品的跳转链接,它又提示你需要登录了,这就是一个无状态的实际效果。
因此此类需要保持用户身份信息的业务,必须要保存用户的状态。
于是引入了Cookie技术,能够保持用户的身份信息,下一次客户端发出请求,服务端能记忆客户端的身份。
没有cookie:

有Cookie:

HTTP请求方法
请求方法
定义client发送给server的请求是什么类型:
- get获取静态数据(查看一张图片)
- post发送提交一些数据(登录表单,提交账户密码数据)
- …等等方法
HTTP请求方法
HTTP请求方法是客户端(如浏览器)与服务器之间进行通信时,用于指定请求类型或所需操作的一组指令。根据HTTP标准,HTTP请求可以使用多种请求方法,这些方法定义了客户端与服务器之间如何交互以及服务器应该如何响应。以下是HTTP请求方法的一些主要类型及其简要说明:
HTTP/1.0定义的请求方法
- GET:
- 用途:用于请求服务器发送资源(如网页、图片等)。GET请求通常用于获取数据,而不对数据进行修改。
- 特点:请求的参数附加在URL后面,多个参数之间用&分隔。由于URL长度有限制(通常在1024K左右),因此GET请求不适合传输大量数据。
- POST:
- 用途:用于向服务器提交数据,以创建或更新资源。POST请求常用于提交表单数据或上传文件。
- 特点:请求的数据包含在请求体中,而不是附加在URL后面。POST请求对数据的长度没有限制(尽管实际限制取决于服务器和浏览器的配置),且相对GET请求更安全(因为数据不会显示在URL中)。
- HEAD:
- 用途:类似于GET请求,但服务器仅返回响应头信息,而不返回实际的内容体。HEAD请求通常用于检查资源的元数据(如资源是否存在、响应头的信息等)。
HTTP/1.1新增的请求方法
- PUT:
- 用途:用于向服务器发送数据以更新现有资源。如果指定的资源不存在,则服务器可能会根据请求创建新资源。PUT请求通常被视为幂等的,即多次执行相同的PUT请求应该产生相同的结果。
- DELETE:
- 用途:请求服务器删除指定的资源。DELETE请求通常包含要删除的资源标识符(如URL)。
- OPTIONS:
- 用途:用于获取服务器针对特定资源所支持的HTTP请求方法。OPTIONS请求也可以用于检查服务器的性能或进行跨域资源共享(CORS)的预检请求。
- PATCH:
- 用途:用于对资源进行部分修改。与PUT请求不同,PATCH请求只更改资源的部分内容,而不是替换整个资源。
- TRACE:
- 用途:用于回显服务器收到的请求,主要用于测试和诊断。TRACE请求允许客户端查看请求在服务器中的处理路径。
- CONNECT:
- 用途:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。CONNECT方法通常用于HTTPS连接,客户端可以通过该隧道发送加密的数据。
其他注意事项
- 安全性:GET请求由于将参数附加在URL上,因此其安全性较低。POST、PUT、DELETE和PATCH等请求方法由于将数据传输在请求体中,因此相对更安全。然而,如果不使用HTTPS,这些请求的数据仍然可能被截获。
- 缓存和书签:GET请求通常可以被缓存和收藏为书签,而POST等请求则不行。
- 数据格式:POST和PUT请求可以传输的数据格式多样,包括表单数据(application/x-www-form-urlencoded)、文件上传(multipart/form-data)等。而GET请求通常只能传输ASCII字符,并且数据会附加在URL上。
请求、响应报文查看
请求和响应报文是HTTP协议中客户端与服务器通信的基本单位。它们包含了请求和响应的详细信息,包括请求方法、资源路径、协议版本、头信息(如Cookie、User-Agent等)以及可选的消息体(如表单数据、文件等)。
要查看请求和响应报文,可以通过以下几种方式:
1. 使用网络调试工具
大多数现代浏览器都内置了网络调试工具,如Chrome浏览器的开发者工具中的“Network”标签页。通过打开该页面,你可以看到所有网络请求的详细信息,包括请求方法、URL、状态码、响应时间、头信息以及预览和原始消息体内容。
2. 使用命令行工具(如curl)
如果你正在使用命令行界面或脚本进行HTTP请求,可以使用像curl这样的命令行工具来查看请求和响应的详细内容。例如:
1 | curl -v -X GET "http://example.com" |
上面的命令将执行一个GET请求到http://example.com,并显示详细的请求过程和响应内容。其中-v参数用于显示详细的输出信息,而-X参数用于指定HTTP请求方法。
3. 通过编程方式分析网络流量(如Wireshark)
对于网络专业人士或安全专家来说,他们可能会使用像Wireshark这样的网络协议分析器来查看和分析网络流量。这些工具能够捕获所有流经网络的流量并展示每个数据包的详细信息,包括TCP/IP头、HTTP头、SSL/TLS握手等。通过这些工具可以更深入地了解网络通信的细节。
4. 使用专门的抓包软件(如Fiddler、Charles Proxy)
Fiddler、Charles Proxy等代理软件可以捕获电脑或移动设备上的网络流量,并提供一个友好的用户界面来查看和编辑请求与响应的内容。这些工具通常被用来调试Web应用、测试API接口或者监控网络性能问题等场景中。
当使用这些工具时,通常需要设置浏览器或其他客户端应用程序以通过代理服务器进行通信。然后你就可以在抓包软件中看到所有的HTTP请求和响应了。
响应状态码
1 | 1、当你 client 发出 get 请求 获取一个图片信息 发出requests |
HTTP状态码是服务器在响应客户端请求时返回的一组标准代码,用来表示服务器对请求的处理结果。HTTP状态码由三位数字组成,根据其类别,可以分为五大类:
- 信息性状态码(100-199)
- 100 Continue:服务器已收到请求头,并且客户端应继续发送请求消息体。
- 101 Switching Protocols:服务器将根据其Upgrade头部字段中指定的协议切换通信协议。
- 成功状态码(200-299)
- 200 OK:请求已成功处理。
- 201 Created:请求已成功,且服务器已创建新的资源。
- 204 No Content:服务器成功处理了请求,但没有返回任何内容。
- 206 Partial Content:服务器成功处理了部分GET请求。
- 重定向状态码(300-399)
- 301 Moved Permanently:资源已被永久移动到新位置。
- 302 Found:资源已被临时移动到新位置。
- 304 Not Modified:未修改文档,服务器返回此状态码时,不会返回文档内容。
- 客户端错误状态码(400-499)
- 400 Bad Request:请求有语法错误或者无法满足。
- 401 Unauthorized:请求需要用户验证。
- 403 Forbidden:服务器拒绝该请求。
- 404 Not Found:无法找到指定位置的资源。这可能是最为人熟知的HTTP状态码之一,通常用于页面或资源不存在的场景中。
- 服务器错误状态码(500-599)
- 500 Internal Server Error:服务器遇到意外情况,无法完成请求。
- 503 Service Unavailable:服务器当前无法处理请求(可能是过载或停机维护)。
其他状态码如502 Bad Gateway、504 Gateway Timeout等也用于表示不同类型的服务器端问题。
每个状态码都包含了特定的含义和用途,它们帮助客户端理解发生了什么以及应该如何响应这些信息。例如当接收到一个404 Not Found的状态码时,浏览器通常会显示一个错误页面告知用户该资源不存在;而接收到200 OK则表示一切正常并会显示所请求的资源内容等。
URL格式
静态资源与web服务器
什么是动态资源
总结梳理(面试背诵)
这些更多的理论,很重要,必须你要做好笔记,去背,记忆,否则面试一问三不知。
1 | 1.dns篇 |
网络设备协议
网络设备的相关协议以及基础配置,以及有线网络和无线网络的基本配置,是网络通信中的重要组成部分。以下是对这些内容的详细阐述:
一、网络设备的相关协议
网络设备的相关协议种类繁多,每种协议都有其特定的应用场景和功能。以下是一些常见的网络设备相关协议:
TCP/IP协议:这是互联网通信的基础协议,包括IP协议和TCP协议等。IP协议负责给每台联网设备分配地址,确保数据能够准确发送到目标设备;TCP协议则负责发现传输中的问题,并请求重新传输,直到数据安全正确地到达目的地。
HTTP协议:超文本传输协议,用于在客户端和服务器之间传输超文本文档,如网页内容。它是一种无状态协议,即每次请求都是独立的。
FTP协议:文件传输协议,用于在客户端和服务器之间传输文件。它支持匿名登录和认证登录,允许用户上传和下载文件。
SMTP协议:简单邮件传输协议,用于在邮件服务器之间传输电子邮件。它定义了邮件的传输规则,包括邮件格式和命令。
POP3协议:邮局协议版本3,用于从邮件服务器上接收邮件。它允许用户在本地计算机上下载邮件,并在服务器上删除邮件。
IMAP协议:互联网消息访问协议,用于在客户端和邮件服务器之间管理邮件。它允许用户在客户端上对邮件进行操作,而不需要将邮件下载到本地计算机。
DNS协议:域名系统协议,用于将域名解析为IP地址。它将域名与IP地址进行映射,并将域名解析请求发送到适当的DNS服务器上。
DHCP协议:动态主机配置协议,用于在局域网中为计算机分配IP地址。它可以自动分配IP地址、子网掩码和默认网关等网络配置信息。
SSH协议:安全外壳协议,用于在不安全的网络上安全地远程登录和执行命令。它通过加密和身份验证机制保证通信的安全性。
这些协议共同构成了网络通信的基础,确保了数据能够在各种设备和系统之间安全、可靠地传输。
二、网络设备的基础配置
网络设备的基础配置通常包括以下几个方面:
管理IP设置:为网络设备分配一个管理IP地址,以便通过该地址远程访问和管理设备。
登录认证信息配置:设置设备的登录用户名和密码,以确保只有授权用户才能访问设备。
系统时间配置:设置设备的系统时间,以确保日志记录、时间同步等功能的准确性。
网络接口配置:根据网络拓扑结构和需求,配置设备的网络接口参数,如IP地址、子网掩码、网关等。
安全策略配置:配置设备的安全策略,如防火墙规则、访问控制列表(ACL)等,以保护网络免受攻击和未经授权的访问。
三、有线网络和无线网络的基本配置
有线网络的基本配置
物理连接:使用网线将计算机、交换机、路由器等设备连接起来,形成物理网络拓扑结构。
IP地址分配:为网络中的每台设备分配一个唯一的IP地址,以便进行通信和数据传输。
子网划分:根据网络规模和需求,将网络划分为不同的子网,以提高网络性能和安全性。
网关和DNS设置:设置网络的默认网关和DNS服务器地址,以确保设备能够正确访问互联网和其他网络资源。
无线网络的基本配置
SSID设置:为无线网络设置一个易于识别的名称(SSID),以便用户能够连接到网络。
安全加密:配置无线网络的安全加密方式(如WPA2-PSK),以保护网络通信的安全性和隐私性。
信道选择:选择一个合适的无线信道,以避免与其他无线网络的干扰。
MAC地址过滤:配置MAC地址过滤规则,以限制只有特定设备才能连接到无线网络。
DHCP服务:启用DHCP服务,为连接到无线网络的设备自动分配IP地址和其他网络配置信息。
通过以上配置,可以确保有线网络和无线网络能够正常运行,并满足用户的通信需求。
NGINX中间件(nginx)
nginx基础篇
web服务器介绍
Web服务器常指的是(world wide web,www)服务器、也是HTTP服务器,主要用于提供网上信息浏览。
我们大部分人接触互联网,都基本上是通过浏览器访问互联网中各种资源。
Web网络服务是一种被动访问的服务程序,即只有接收到互联网中其他主机发出的请求后才会响应,最终用于提供服务程序的Web服务器会通过HTTP(超文本传输协议)或HTTPS(安全超文本传输协议)把请求的内容传送给用户。
Unix和Linux平台下的常用Web服务器常见有:
Apache
Nginx
Lighttpd
Tomcat
IBM WebSphere
其中最为广泛的是Nginx,在Windows平台上最常用的是微软的IIS(Internet Information Server,互联网信息服务)是Windows系统中默认的Web服务程序。
Apache

Apache是世界主流的Web服务器,世界上大多著名网站都是Apache搭建,优势在于开放源代码,开发维护团队强大、支持跨平台应用(Unix、Linux、Windows),强大的移植性等优点。
Apache属于重量级产品,功能以模块化定制,消耗内存较高,性能稍弱于其他轻量级Web服务器。
Lighttpd

Lighttpd是一款高安全性、快速、且灵活的Web服务器产品,专为高性能环境而设计,相比其他Web服务器,内存占用量小,能够有效管理CPU负载,支持(FastCGI、SCGI,Auth,输出压缩,url重写,别名)等重要功能,是Nginx的重要对手之一。
Tomcat

Tomcat是一个开源、运行基于Java的Web应用软件的容器,Tomcat Server根据servlet和JSP规范执行,但是Tomcat对于平台文件、高并发处理较弱。
要使用Tomcat需要对Java的应用部署有足够的了解。
IBM WebSphere

WebSphere Applicaiton Server是一种强大的Web应用服务器,基于Java的应用环境、建立、部署和管理网站应用。
Microsoft IIS

微软的IIS是一种灵活,安全易管理的Web服务器,从流媒体到Web应用程序,IIS提供了图形化的管理界面,用于配置和管理网络服务。
llS是一整套Web组件,包含了Web服务器,FTP服务器,SMTP服务器等常用的网页浏览、文件传输,邮件新闻等功能。
缺点是只能运行在Windows平台,还得购买商业化的操作系统。
Nginx

Nginx是俄罗斯人lgor Sysoev(伊戈尔·塞索耶夫)开发的一款高性能的HTTP和反向代理服务器。
Nginx以高效的epoll、kqueue、eventport作为网络IO模型,在高并发场景下,Nginx能够轻松支持5w并发连接数的响应,并且消耗的服务器内存、CPU等系统资源消耗却很低,运行非常稳定。
当前想让nginx支持5万并发,甚至百万级并发, 都是可以的,但需要做很多的优化工作,如:
1 | 想至少支持5万并发的基本调优 |
国内著名站点,新浪博客、网易、淘宝、豆瓣、迅雷等大型网站都在使用Nginx作为web服务器或是反向代理服务器。
异步非阻塞的高性能IO模型,任你有N个请求来临,nginx都临危不惧,从容解析响应。
为何选择nginx

在互联网的快速普及,全球化、物联网的迅速发展,世界排名前3的分别是Apache、llS、Nginx,而Nginx一直在呈现增长趋势。
在线自动生成nginx配置文件
https://www.digitalocean.com/community/tools/nginx?global.app.lang=zhCN
可以自由选择所需的应用,生成nginx配置作为参考。
1 | 根据业务需求,自动生成复杂的nginx配置文件,提供参考。 |
nginx介绍
1、nginx是什么
1 | 1.nginx是一个高性能的HTTP服务器、反向代理服务器。 |
2、为什么选择nginx
1 | 1、每一家公司都会用到nginx |
3、nginx重要特性
1 | 1.官网直接获取源码,免费用,讲道理这种高性能的软件,是很责的。 |
4.企业用nginx做什么
1 | 1.提供静态页面展示,网页服务 |
nginx架构
nginx是多进程架构,当启动nginx会使用root创建master进程,由master进程创建多个worker进程。
1 | [root@yuchao-tx-server ~]#ps -ef|grep nginx |grep -v grep |
master进程
包工头进程,管理nginx的数据,创建worker工作进程。
master主进程原理
1 | 1.启动时检查nginx.conf是否正确,语法错误 --nginx -t 命令给master进程发送信号,去检测配置文件 |

worker进程
1 | 1.实际处理client网络请求的是worker |
nginx进程通信

nginx处理http请求流程

nginx动手环节
nginx模块介绍
模块解释
1 | Nginx模块名称模块作用 |
模块官网
官网文档
https://nginx.org/en/docs/ 所有模块
1 | nginx核心功能都以插件的方式,是否安装插件,开启该功能决定是否有各种功能。 |


nginx部署实践
nginx安装形式
- 源代码编译安装,优点
- 版本,可以获取官网最新的软件包,甚至最新测试版,都可以直接编译安装
- 还有稳定版本
- 自由定义,安装路径自由定义,·自由定义第三方插件
- 缺点,安装步骤繁琐,耗时太长,看你要装多少个模块,编译添加的模块多,安装的就更久
- rpm安装
- 得提前准备好nginx本身的rpm包,以及相关依赖的rpm包
- 用于离线安装nginx的环境
- yum安装,你会用哪些形式的仓库?
- 阿里云第三方仓库(centos-base.repo,epel.repo)
- 这个其实都不靠谱。
- 自建yum仓库(得提前准备好nginx本身的rpm包,以及相关依赖的rpm包)
- nginx官网仓库(获取官网最新稳定版的yum源仓库)
- yum一键安装,省心省事,版本也是有一定的保障的,rpm的安全性也是有保障的
- 阿里云第三方仓库(centos-base.repo,epel.repo)
1 | 官网yum仓库 |
编译安装
官网
1 | https ://nginx.org/en/docs/configure.html |
超哥的文档
1 | 1.创建用户 |
开始编译,编译三部曲
1 | 0.查看稿译参数帮助信息 |
创建软连接
1 | [ root@web-9 /yuchao-linux-data/nginx-1.19.0]#ln -s /opt/nginx-1-19-0/ /opt/nginx[root@web-9 /yuchao-linux-data/nginx-1.19.0]# |
默认的nginx安装目录
1 | [root@web-9 /yuchao-linux-data/nginx-1.19.e]#ls /opt/nginx conf html logssbin |
检查语法
1 | [root@seb-9 /opt]#/opt/nginx/sbin/nginx -t |
启动nginx
1 | 先不着急配置PATH,先绝对路径启动 |
停止nginx
1 | [root@web-9 /opt]#/opt/nginx/sbin/nginx -s stop |
测试nginx
1 | [root@web-9 /opt]#/opt/nginx/sbin/nginx -c /opt/nginx/conf/nginx.conf |

yum安装
epel源安装就不操作了
1 | 1.配置阿里云yum epel源 |
官网nginx源
1 | 官网文档 |
于超文档
1 | 1.安装yum工具包 |
nginx配置文件详解
nginx虚拟主机
web基础协议
Docker容器的部署与使用
同学们,在前两天我们学习了Linux操作系统的常见命令以及如何在Linux上部署一个单体项目。大家想一想自己最大的感受是什么?
我相信,除了个别天赋异禀的同学以外,大多数同学都会有相同的感受,那就是麻烦。核心体现在三点:
- 命令太多了,记不住
- 软件安装包名字复杂,不知道去哪里找
- 安装和部署步骤复杂,容易出错
其实上述问题不仅仅是新手,即便是运维在安装、部署的时候一样会觉得麻烦、容易出错。
特别是我们即将进入微服务阶段学习,微服务项目动辄就是几十台、上百台服务需要部署,有些大型项目甚至达到数万台服务。而由于每台服务器的运行环境不同,你写好的安装流程、部署脚本并不一定在每个服务器都能正常运行,经常会出错。这就给系统的部署运维带来了很多困难。
那么,有没有一种技术能够避免部署对服务器环境的依赖,减少复杂的部署流程呢?
答案是肯定的,这就是我们今天要学习的Docker技术。你会发现,有了Docker以后项目的部署如丝般顺滑,大大减少了运维工作量。
即便你对Linux不熟悉,你也能轻松部署各种常见软件、Java项目。
通过今天的学习,希望大家能达成下面的学习目标:
- 能利用Docker部署常见软件
- 能利用Docker打包并部署Java应用
- 理解Docker数据卷的基本作用
- 能看懂DockerCompose文件
1.快速入门
要想让Docker帮我们安装和部署软件,肯定要保证你的机器上有Docker. 由于大家的操作系统各不相同,安装方式也不同。为了便于大家学习,我们统一在CentOS的虚拟机中安装Docker,统一学习环境。
注意:使用MacBook的同学也请利用 VMwareFusion来安装虚拟机,并在虚拟机中学习Docker使用。
安装方式参考文档:《安装Docker》
1.1.部署Docker容器
安装docker :smile: :heart: :+1:
第一步,打开官网
第二布 在Linux系统上卸载旧版本

1 | sudo yum remove docker \ |

第三步 安装依赖
1 | sudo yum install -y yum-utils |
第四步 下载docker
1 | sudo yum-config-manager --add-repo |
第五步 安装docker
1 | sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin |

启动docker服务
1 | sudo systemctl start docker |
运行第一个docker案例
1 | sudo docker run hello-world |
第一个docker案例运行成功

运行第一个案例失败
问题:连接失败,访问超时
还是镜像的问题,在/etc/docker/中创建一个daemon.json文件
1 | cd /etc/docker |
重启docker服务
重启守护进程
1 | sudo systemctl daemon-reload |
重启服务
1 | sudo systemctl restart docker |
如果需要强制启动Docker服务,可以先重置失败状态,然后再次尝试启动:
1 | systemctl status docker.service |
清理缓存
1 | 清理Docker缓存:运行 docker system prune --all 清除无用的缓存和镜像。 |
问题描述:
在刚安装完docker,执行sudo docker pull hello-world 来测试 docker 是否安装成功时,报错:
1 | Unable to find image 'hello-world:latest' locally |
原因及解决方案:
Docker 守护进程作为一个后台服务运行,它并不会读取或继承用户的 shell 环境变量(除非在启动时特别指定)。为了确保 Docker 在拉取镜像或进行其他网络通讯时能够通过代理服务器,必须在 Docker 的服务配置中设置这些代理变量。
如果你的代理服务器运行在本地机器上,并且使用的端口是 7890,你需要在 Docker 的配置文件中设置这些代理参数以确保 Docker 通过这个本地代理端口进行网络通信。以下是具体的配置文件内容:
创建或编辑 /etc/systemd/system/docker.service.d/http-proxy.conf 文件:
首先,你需要确保有一个目录来存放 Docker 的服务配置。如果这个目录还不存在,你可以使用以下命令创建它:
1 | sudo mkdir -p /etc/systemd/system/docker.service.d |
接着,使用文本编辑器创建或编辑 http-proxy.conf 文件:
1 | sudo vim /etc/systemd/system/docker.service.d/http-proxy.conf |
在打开的编辑器中,输入以下内容:
1 | [Service] |
这里配置了 HTTP 和 HTTPS 代理都指向 127.0.0.1 的 7890 端口。NO_PROXY 环境变量指定了不需要通过代理访问的地址列表,通常包括本地地址和内部网络地址等。
保存并关闭编辑器:
如果你使用的是 nano 编辑器,可以通过按 Ctrl+O 保存文件,然后按 Ctrl+X 退出编辑器。
如果用的是vim,则按esc键,然后输入:wq保存退出。
重新加载系统守护进程并重启 Docker 服务:
为了让这些更改生效,你需要重新加载系统守护进程并重启 Docker 服务:
1 | sudo systemctl daemon-reload |
这样,Docker 服务在启动和运行时就会使用本地的 7890 端口的代理服务器进行网络通信。可以通过尝试拉取一个 Docker 镜像来测试代理配置是否生效:
1 | sudo docker run hello-world |
如果这个命令能够成功执行,并且能够从 Docker Hub 拉取镜像,那么就说明你的代理配置是正确的。如果遇到连接问题,需要检查本地代理服务器是否正常运行在指定端口上。
成功运行的输出:
1 | Unable to find image 'hello-world:latest' locally |
1.2.部署MySQL
首先,我们利用Docker来安装一个MySQL软件,大家可以对比一下之前传统的安装方式,看看哪个效率更高一些。
如果是利用传统方式部署MySQL,大概的步骤有:
- 搜索并下载MySQL安装包
- 上传至Linux环境
- 编译和配置环境
- 安装
而使用Docker安装,仅仅需要一步即可,在命令行输入下面的命令(建议采用CV大法):
1 | docker run -d \ |
运行效果如图:
MySQL安装完毕!通过任意客户端工具即可连接到MySQL.
大家可以发现,当我们执行命令后,Docker做的第一件事情,是去自动搜索并下载了MySQL,然后会自动运行MySQL,我们完全不用插手,是不是非常方便。
而且,这种安装方式你完全不用考虑运行的操作系统环境,它不仅仅在CentOS系统是这样,在Ubuntu系统、macOS系统、甚至是装了WSL的Windows下,都可以使用这条命令来安装MySQL。
要知道,不同操作系统下其安装包、运行环境是都不相同的!如果是手动安装,必须手动解决安装包不同、环境不同的、配置不同的问题!
而使用Docker,这些完全不用考虑。就是因为Docker会自动搜索并下载MySQL。注意:这里下载的不是安装包,而是镜像。镜像中不仅包含了MySQL本身,还包含了其运行所需要的环境、配置、系统级函数库。因此它在运行时就有自己独立的环境,就可以跨系统运行,也不需要手动再次配置环境了。这套独立运行的隔离环境我们称为容器。
说明:
- 镜像:英文是image
- 容器:英文是container
因此,Docker安装软件的过程,就是自动搜索下载镜像,然后创建并运行容器的过程。
Docker会根据命令中的镜像名称自动搜索并下载镜像,那么问题来了,它是去哪里搜索和下载镜像的呢?这些镜像又是谁制作的呢?
Docker官方提供了一个专门管理、存储镜像的网站,并对外开放了镜像上传、下载的权利。Docker官方提供了一些基础镜像,然后各大软件公司又在基础镜像基础上,制作了自家软件的镜像,全部都存放在这个网站。这个网站就成了Docker镜像交流的社区:
Docker
基本上我们常用的各种软件都能在这个网站上找到,我们甚至可以自己制作镜像上传上去。
像这种提供存储、管理Docker镜像的服务器,被称为DockerRegistry,可以翻译为镜像仓库。DockerHub网站是官方仓库,阿里云、华为云会提供一些第三方仓库,我们也可以自己搭建私有的镜像仓库。
官方仓库在国外,下载速度较慢,一般我们都会使用第三方仓库提供的镜像加速功能,提高下载速度。而企业内部的机密项目,往往会采用私有镜像仓库。
总之,镜像的来源有两种:
- 基于官方基础镜像自己制作
- 直接去DockerRegistry下载
::: warning
总结一下:
Docker本身包含一个后台服务,我们可以利用Docker命令告诉Docker服务,帮助我们快速部署指定的应用。Docker服务部署应用时,首先要去搜索并下载应用对应的镜像,然后根据镜像创建并运行容器,应用就部署完成了。
:::
用一幅图标示如下:
1.2.命令解读
利用Docker快速的安装了MySQL,非常的方便,不过我们执行的命令到底是什么意思呢?
1 | docker run -d \ |
解读:
docker run -d:创建并运行一个容器,-d则是让容器以后台进程运行--name mysql: 给容器起个名字叫mysql,你可以叫别的-p 3306:3306: 设置端口映射。- 容器是隔离环境,外界不可访问。但是可以将宿主机端口映射容器内到端口,当访问宿主机指定端口时,就是在访问容器内的端口了。
- 容器内端口往往是由容器内的进程决定,例如MySQL进程默认端口是3306,因此容器内端口一定是3306;而宿主机端口则可以任意指定,一般与容器内保持一致。
- 格式:
-p 宿主机端口:容器内端口,示例中就是将宿主机的3306映射到容器内的3306端口
-e TZ=Asia/Shanghai: 配置容器内进程运行时的一些参数- 格式:
-e KEY=VALUE,KEY和VALUE都由容器内进程决定 - 案例中,
TZ=Asia/Shanghai是设置时区;MYSQL_ROOT_PASSWORD=123是设置MySQL默认密码
- 格式:
mysql: 设置镜像名称,Docker会根据这个名字搜索并下载镜像- 格式:
REPOSITORY:TAG,例如mysql:8.0,其中REPOSITORY可以理解为镜像名,TAG是版本号 - 在未指定
TAG的情况下,默认是最新版本,也就是mysql:latest
- 格式:
镜像的名称不是随意的,而是要到DockerRegistry中寻找,镜像运行时的配置也不是随意的,要参考镜像的帮助文档,这些在DockerHub网站或者软件的官方网站中都能找到。
如果我们要安装其它软件,也可以到DockerRegistry中寻找对应的镜像名称和版本,阅读相关配置即可。
2.Docker基础
接下来,我们一起来学习Docker使用的一些基础知识,为将来部署项目打下基础。具体用法可以参考Docker官方文档:
Docker Docs: How to build, share, and run applications
2.1.常见命令
首先我们来学习Docker中的常见命令,可以参考官方文档:
Use the Docker command line
2.1.1.命令介绍
其中,比较常见的命令有:
| 命令 | 说明 | 文档地址 |
|---|---|---|
| docker pull | 拉取镜像 | docker pull |
| docker push | 推送镜像到DockerRegistry | docker push |
| docker images | 查看本地镜像 | docker images |
| docker rmi | 删除本地镜像 | docker rmi |
| docker run | 创建并运行容器(不能重复创建) | docker run |
| docker stop | 停止指定容器 | docker stop |
| docker start | 启动指定容器 | docker start |
| docker restart | 重新启动容器 | docker restart |
| docker rm | 删除指定容器 | docker rm |
| docker ps | 查看容器 | docker ps |
| docker logs | 查看容器运行日志 | docker logs |
| docker exec | 进入容器 | docker exec |
| docker save | 保存镜像到本地压缩文件 | docker save |
| docker load | 加载本地压缩文件到镜像 | docker load |
| docker inspect | 查看容器详细信息 | docker inspect |
用一副图来表示这些命令的关系:
补充:
默认情况下,每次重启虚拟机我们都需要手动启动Docker和Docker中的容器。通过命令可以实现开机自启:
1 | Docker开机自启 |
2.1.2.演示
教学环节说明:我们以Nginx为例给大家演示上述命令。
1 | 第1步,去DockerHub查看nginx镜像仓库及相关信息 |
2.1.3.命令别名
给常用Docker命令起别名,方便我们访问:
1 | 修改/root/.bashrc文件 |
内容如下:
1 | .bashrc |
然后,执行命令使别名生效
1 | source /root/.bashrc |
接下来,试试看新的命令吧。
2.2.数据卷
容器是隔离环境,容器内程序的文件、配置、运行时产生的数据都在容器内部,与容器绑定。但在某些情况下这回带来一些问题,大家思考一下:
- 如果要升级MySQL版本,需要销毁旧容器,那么数据岂不是跟着被销毁了?
- MySQL、Nginx容器运行后,如果我要修改其中的某些配置该怎么办?
- 我想要让Nginx代理容器外部的静态资源怎么办?
可见,配置与数据存放在容器内是非常不方便的,而且容易出现问题。
因此,容器提供程序的运行环境,但是程序运行产生的数据、程序运行依赖的配置都应该与容器解耦。
2.2.1.什么是数据卷
数据卷(volume)是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁。
以Nginx为例,我们知道Nginx中有两个关键的目录:
html:放置一些静态资源conf:放置配置文件
如果我们要让Nginx代理我们的静态资源,最好是放到html目录;如果我们要修改Nginx的配置,最好是找到conf下的nginx.conf文件。
但遗憾的是,容器运行的Nginx所有的文件都在容器内部,读写都非常不方便。所以我们通常会利用数据卷将两个目录与宿主机目录关联,方便我们操作。如图:
在上图中:
- 我们创建了两个数据卷:
conf、html - Nginx容器内部的
conf目录和html目录分别与两个数据卷关联。 - 而数据卷conf和html分别指向了宿主机的
/var/lib/docker/volumes/conf/_data目录和/var/lib/docker/volumes/html/_data目录
这样以来,容器内的conf和html目录就 与宿主机的conf和html目录关联起来,我们称为挂载。此时,我们操作宿主机的/var/lib/docker/volumes/html/_data就是在操作容器内的/usr/share/nginx/html/_data目录。只要我们将静态资源放入宿主机对应目录,就可以被Nginx代理了。
:::warning
小提示:/var/lib/docker/volumes这个目录就是默认的存放所有容器数据卷的目录,其下再根据数据卷名称创建新目录,格式为/数据卷名/_data。
为什么不让容器目录直接指向宿主机目录呢?
- 因为直接指向宿主机目录就与宿主机强耦合了,如果切换了环境,宿主机目录就可能发生改变了。由于容器一旦创建,目录挂载就无法修改,这样容器就无法正常工作了。
- 但是容器指向数据卷,一个逻辑名称,而数据卷再指向宿主机目录,就不存在强耦合。如果宿主机目录发生改变,只要改变数据卷与宿主机目录之间的映射关系即可。
不过,我们通过由于数据卷目录比较深,不好寻找,通常我们也允许让容器直接与宿主机目录挂载而不使用数据卷,具体参考2.2.3小节。
:::
2.2.2.数据卷命令
数据卷的相关命令有:
| 命令 | 说明 | 文档地址 |
|---|---|---|
| docker volume create | 创建数据卷 | docker volume create |
| docker volume ls | 查看所有数据卷 | docker volume ls |
| docker volume rm | 删除指定数据卷 | docker volume prune |
| docker volume inspect | 查看某个数据卷的详情 | docker volume inspect |
| docker volume prune | 清除数据卷 | docker volume prune |
注意:容器与数据卷的挂载要在创建容器时配置,对于创建好的容器,是不能设置数据卷的。而且创建容器的过程中,数据卷会自动创建。
教学演示环节:演示一下nginx的html目录挂载
1 | 1.首先创建容器并指定数据卷,注意通过 -v 参数来指定数据卷 |
教学演示环节:演示一下MySQL的匿名数据卷
1 | 1.查看MySQL容器详细信息 |
我们关注两部分内容,第一是.Config.Volumes部分:
1 | { |
可以发现这个容器声明了一个本地目录,需要挂载数据卷,但是数据卷未定义。这就是匿名卷。
然后,我们再看结果中的.Mounts部分:
1 | { |
可以发现,其中有几个关键属性:
- Name:数据卷名称。由于定义容器未设置容器名,这里的就是匿名卷自动生成的名字,一串hash值。
- Source:宿主机目录
- Destination : 容器内的目录
上述配置是将容器内的/var/lib/mysql这个目录,与数据卷29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f挂载。于是在宿主机中就有了/var/lib/docker/volumes/29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f/_data这个目录。这就是匿名数据卷对应的目录,其使用方式与普通数据卷没有差别。
接下来,可以查看该目录下的MySQL的data文件:
1 | ls -l /var/lib/docker/volumes/29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f/_data |
:::warning
注意:每一个不同的镜像,将来创建容器后内部有哪些目录可以挂载,可以参考DockerHub对应的页面
:::
2.2.3.挂载本地目录或文件
可以发现,数据卷的目录结构较深,如果我们去操作数据卷目录会不太方便。在很多情况下,我们会直接将容器目录与宿主机指定目录挂载。挂载语法与数据卷类似:
1 | 挂载本地目录 |
:::warning
注意:本地目录或文件必须以 / 或 ./开头,如果直接以名字开头,会被识别为数据卷名而非本地目录名。
:::
例如:
1 | -v mysql:/var/lib/mysql # 会被识别为一个数据卷叫mysql,运行时会自动创建这个数据卷 |
教学演示,删除并重新创建mysql容器,并完成本地目录挂载:
- 挂载
/root/mysql/data到容器内的/var/lib/mysql目录 - 挂载
/root/mysql/init到容器内的/docker-entrypoint-initdb.d目录(初始化的SQL脚本目录) - 挂载
/root/mysql/conf到容器内的/etc/mysql/conf.d目录(这个是MySQL配置文件目录)
在课前资料中已经准备好了mysql的init目录和conf目录:
以及对应的初始化SQL脚本和配置文件:

其中,hm.cnf主要是配置了MySQL的默认编码,改为utf8mb4;而hmall.sql则是后面我们要用到的黑马商城项目的初始化SQL脚本。
我们直接将整个mysql目录上传至虚拟机的/root目录下:
接下来,我们演示本地目录挂载:
1 | 1.删除原来的MySQL容器 |
2.3.自定义镜像
前面我们一直在使用别人准备好的镜像,那如果我要部署一个Java项目,把它打包为一个镜像该怎么做呢?
2.3.1.镜像结构
要想自己构建镜像,必须先了解镜像的结构。
之前我们说过,镜像之所以能让我们快速跨操作系统部署应用而忽略其运行环境、配置,就是因为镜像中包含了程序运行需要的系统函数库、环境、配置、依赖。
因此,自定义镜像本质就是依次准备好程序运行的基础环境、依赖、应用本身、运行配置等文件,并且打包而成。
举个例子,我们要从0部署一个Java应用,大概流程是这样:
- 准备一个Linux环境(CentOS或者Ubuntu均可)
- 安装并配置JDK
- 上传Jar包
- 运行jar包
那因此,我们打包镜像也是分成这么几步:
- 准备Linux运行环境(java项目并不需要完整的操作系统,仅仅是基础运行环境即可)
- 安装并配置JDK
- 拷贝jar包
- 配置启动脚本
上述步骤中的每一次操作其实都是在生产一些文件(系统运行环境、函数库、配置最终都是磁盘文件),所以镜像就是一堆文件的集合。
但需要注意的是,镜像文件不是随意堆放的,而是按照操作的步骤分层叠加而成,每一层形成的文件都会单独打包并标记一个唯一id,称为Layer(层)。这样,如果我们构建时用到的某些层其他人已经制作过,就可以直接拷贝使用这些层,而不用重复制作。
例如,第一步中需要的Linux运行环境,通用性就很强,所以Docker官方就制作了这样的只包含Linux运行环境的镜像。我们在制作java镜像时,就无需重复制作,直接使用Docker官方提供的CentOS或Ubuntu镜像作为基础镜像。然后再搭建其它层即可,这样逐层搭建,最终整个Java项目的镜像结构如图所示:
2.3.2.Dockerfile
由于制作镜像的过程中,需要逐层处理和打包,比较复杂,所以Docker就提供了自动打包镜像的功能。我们只需要将打包的过程,每一层要做的事情用固定的语法写下来,交给Docker去执行即可。
而这种记录镜像结构的文件就称为Dockerfile,其对应的语法可以参考官方文档:
Dockerfile 官方文档
其中的语法比较多,比较常用的有:
| 指令 | 说明 | 示例 |
|---|---|---|
| FROM | 指定基础镜像 | FROM centos:6 |
| ENV | 设置环境变量,可在后面指令使用 | ENV key value |
| COPY | 拷贝本地文件到镜像的指定目录 | COPY ./xx.jar /tmp/app.jar |
| RUN | 执行Linux的shell命令,一般是安装过程的命令 | RUN yum install gcc |
| EXPOSE | 指定容器运行时监听的端口,是给镜像使用者看的 | EXPOSE 8080 |
| ENTRYPOINT | 镜像中应用的启动命令,容器运行时调用 | ENTRYPOINT java -jar xx.jar |
例如,要基于Ubuntu镜像来构建一个Java应用,其Dockerfile内容如下:
1 | # 指定基础镜像 |
同学们思考一下:以后我们会有很多很多java项目需要打包为镜像,他们都需要Linux系统环境、JDK环境这两层,只有上面的3层不同(因为jar包不同)。如果每次制作java镜像都重复制作前两层镜像,是不是很麻烦。
所以,就有人提供了基础的系统加JDK环境,我们在此基础上制作java镜像,就可以省去JDK的配置了:
1 | # 基础镜像 |
是不是简单多了。
2.3.3.构建镜像
当Dockerfile文件写好以后,就可以利用命令来构建镜像了。
在课前资料中,我们准备好了一个demo项目及对应的Dockerfile:
首先,我们将课前资料提供的docker-demo.jar包以及Dockerfile拷贝到虚拟机的/root/demo目录:
然后,执行命令,构建镜像:
1 | 进入镜像目录 |
命令说明:
docker build: 就是构建一个docker镜像-t docker-demo:1.0:-t参数是指定镜像的名称(repository和tag).: 最后的点是指构建时Dockerfile所在路径,由于我们进入了demo目录,所以指定的是.代表当前目录,也可以直接指定Dockerfile目录:
1 | 直接指定Dockerfile目录 |
结果:
查看镜像列表:
1 | 查看镜像列表: |
然后尝试运行该镜像:
1 | 1.创建并运行容器 |
2.4.网络
上节课我们创建了一个Java项目的容器,而Java项目往往需要访问其它各种中间件,例如MySQL、Redis等。现在,我们的容器之间能否互相访问呢?我们来测试一下
首先,我们查看下MySQL容器的详细信息,重点关注其中的网络IP地址:
1 | 1.用基本命令,寻找Networks.bridge.IPAddress属性 |
发现可以互联,没有问题。
但是,容器的网络IP其实是一个虚拟的IP,其值并不固定与某一个容器绑定,如果我们在开发时写死某个IP,而在部署时很可能MySQL容器的IP会发生变化,连接会失败。
所以,我们必须借助于docker的网络功能来解决这个问题,官方文档:
docker network
常见命令有:
| 命令 | 说明 | 文档地址 |
|---|---|---|
| docker network create | 创建一个网络 | docker network create |
| docker network ls | 查看所有网络 | docker network ls |
| docker network rm | 删除指定网络 | docker network rm |
| docker network prune | 清除未使用的网络 | docker network prune |
| docker network connect | 使指定容器连接加入某网络 | docker network connect |
| docker network disconnect | 使指定容器连接离开某网络 | docker network disconnect |
| docker network inspect | 查看网络详细信息 | docker network inspect |
教学演示:自定义网络
1 | 1.首先通过命令创建一个网络 |
OK,现在无需记住IP地址也可以实现容器互联了。
:::warning
总结:
- 在自定义网络中,可以给容器起多个别名,默认的别名是容器名本身
- 在同一个自定义网络中的容器,可以通过别名互相访问
:::
3.项目部署
好了,我们已经熟悉了Docker的基本用法,接下来可以尝试部署项目了。
在课前资料中已经提供了一个黑马商城项目给大家,如图:

项目说明:
- hmall:商城的后端代码
- hmall-portal:商城用户端的前端代码
- hmall-admin:商城管理端的前端代码
部署的容器及端口说明:
| 项目 | 容器名 | 端口 | 备注 |
|---|---|---|---|
| hmall | hmall | 8080 | 黑马商城后端API入口 |
| hmall-portal | nginx | 18080 | 黑马商城用户端入口 |
| hmall-admin | 18081 | 黑马商城管理端入口 | |
| mysql | mysql | 3306 | 数据库 |
在正式部署前,我们先删除之前的nginx、dd两个容器:
1 | docker rm -f nginx dd |
mysql容器中已经准备好了商城的数据,所以就不再删除了。
3.1.部署Java项目
hmall项目是一个maven聚合项目,使用IDEA打开hmall项目,查看项目结构如图:
我们要部署的就是其中的hm-service,其中的配置文件采用了多环境的方式:
其中的application-dev.yaml是部署到开发环境的配置,application-local.yaml是本地运行时的配置。
查看application.yaml,你会发现其中的JDBC地址并未写死,而是读取变量:
这两个变量在application-dev.yaml和application-local.yaml中并不相同:
在dev开发环境(也就是Docker部署时)采用了mysql作为地址,刚好是我们的mysql容器名,只要两者在一个网络,就一定能互相访问。
我们将项目打包:
结果:
将hm-service目录下的Dockerfile和hm-service/target目录下的hm-service.jar一起上传到虚拟机的root目录:
部署项目:
1 | 1.构建项目镜像,不指定tag,则默认为latest |
测试,通过浏览器访问:http://你的虚拟机地址:8080/search/list
3.2.部署前端
hmall-portal和hmall-admin是前端代码,需要基于nginx部署。在课前资料中已经给大家提供了nginx的部署目录:
其中:
html是静态资源目录,其中已经包含了hmall-portal以及hmall-adminnginx.conf是nginx的配置文件,主要是完成对html下的两个静态资源目录做代理
我们现在要做的就是把整个nginx目录上传到虚拟机的/root目录下:
然后创建nginx容器并完成两个挂载:
- 把
/root/nginx/nginx.conf挂载到/etc/nginx/nginx.conf - 把
/root/nginx/html挂载到/etc/nginx/html
由于需要让nginx同时代理hmall-portal和hmall-admin两套前端资源,因此我们需要暴露两个端口:
- 18080:对应hmall-portal
- 18081:对应hmall-admin
命令如下:
1 | docker run -d \ |
测试,通过浏览器访问:http://你的虚拟机ip:18080
3.3.DockerCompose
大家可以看到,我们部署一个简单的java项目,其中包含3个容器:
- MySQL
- Nginx
- Java项目
而稍微复杂的项目,其中还会有各种各样的其它中间件,需要部署的东西远不止3个。如果还像之前那样手动的逐一部署,就太麻烦了。
而Docker Compose就可以帮助我们实现多个相互关联的Docker容器的快速部署。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器。
3.3.1.基本语法
docker-compose.yml文件的基本语法可以参考官方文档:
Compose file version 3 reference
docker-compose文件中可以定义多个相互关联的应用容器,每一个应用容器被称为一个服务(service)。由于service就是在定义某个应用的运行时参数,因此与docker run参数非常相似。
举例来说,用docker run部署MySQL的命令如下:
1 | docker run -d \ |
如果用docker-compose.yml文件来定义,就是这样:
1 | version: "3.8" |
对比如下:
| docker run 参数 | docker compose 指令 | 说明 |
|---|---|---|
| –name | container_name | 容器名称 |
| -p | ports | 端口映射 |
| -e | environment | 环境变量 |
| -v | volumes | 数据卷配置 |
| –network | networks | 网络 |
明白了其中的对应关系,相信编写docker-compose文件应该难不倒大家。
黑马商城部署文件:
1 | version: "3.8" |
3.3.2.基础命令
编写好docker-compose.yml文件,就可以部署项目了。常见的命令:
Overview of docker compose CLI
基本语法如下:
1 | docker compose [OPTIONS] [COMMAND] |
其中,OPTIONS和COMMAND都是可选参数,比较常见的有:
| 类型 | 参数或指令 | 说明 |
|---|---|---|
| Options | -f | 指定compose文件的路径和名称 |
| -p | 指定project名称。project就是当前compose文件中设置的多个service的集合,是逻辑概念 | |
| Commands | up | 创建并启动所有service容器 |
| down | 停止并移除所有容器、网络 | |
| ps | 列出所有启动的容器 | |
| logs | 查看指定容器的日志 | |
| stop | 停止容器 | |
| start | 启动容器 | |
| restart | 重启容器 | |
| top | 查看运行的进程 | |
| exec | 在指定的运行中容器中执行命令 |
教学演示:
1 | 1.进入root目录 |
打开浏览器,访问:http://yourIp:8080
4.作业
尝试用Docker的方式部署项目1