👨?🏫 Docker And Nginx.
简单学习Docker。
先理解一个问题:什么是容器?
我以前简单学Docker 的时候,用Docker部署Redis和MySQL的时候,我以为容器仅仅只是一个容器 ,在这里我首先要纠正一点就是,不要把容器想成简单的容器,可以把每一个容器想象成一个Linux环境,我认为这一点也是Docker比较牛的地方.
🔖 一、Docker学习。
参考:Docker 教程 | 菜鸟教程 (runoob.com)
💡 1.1 什么是Docker.
Docker 是一个开源的应用容器引擎,基于Go实现,遵从Apache2.0协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器上,这里所说的容器和上面我提到的容器是一个容器,容器是完全使用沙箱机制,可以这么理解就是,一台Linux部署了5个Docker容器,那么这一台电脑可以相当于6台电脑去使用,容器可以比作是Linux中的Linux,这个我也是在学习过程中才理解的.
不幸的是Docker开始收费了,但是幸运的是Docker提供社区版本来供我们学习.
💡 1.2 Docker 有什么优点.
现在,各个大厂都在使用Docker和K8S来进行上云,既然这么多大公司都在用,那么就说明,Docker肯定是有其非常亮眼的优势的,现在我们就来分析一下。
Docker 使您能够将应用程序与基础架构分开,从而可以快速交付软件。借助Docker可以以管理应用程序的方式来管理基础架构。通过利用Docker的方法来快速交付、测试、部署代码。
💡 1.3 Docker 整体将架构.
参考:[Docker] Docker整体架构图 - dhcn - 博客园 (cnblogs.com)
Docker 是基于C/S 模式的架构的,其通过 DocekrClient 和 与 Docker Daemon 建立通信,使用远程API来管理和创建Docker容器. 其可以通过HTTP API 形式通信也可以通过Socket方式进行通信.
Docker Client 通过发送请求到 Docker Server中,Docker Server 根据路由以及请求来调用Engine中的各个不同的Job来完成本次请求操作,而之后各个Job完成自己的任务向Engine返回即可.
💡 1.4 Docker安装.
因为DEV-CLOUD内部集成了Docker,所以这里省略. 如果想要在自己服务器上安装docker的话,参考上面 Docker 教程
💡 1.5 Docker 中容器和镜像的关系.
Docker中容器和镜像之间的关系就相当于操作系统中的进程和程序的关系。
💡 1.5 Docker命令.
下面是一些基本的Docker命令,一些高级的Docker命令没有列出来.
docker search nginx 搜索某个镜像.docker pull nginx 下载nginx@latest.docker images : 查看当前Docker中存在的镜像.docker ps :查看当前未关闭的容器.docker ps -a :查看所有容器.docekr rm imagname 删除指定容器.docker rmi imgid 删除指定镜像.docker run --name 容器名字 -p 18088:18088 -d 镜像名字 , 关于docker run 的命令参数可以通过命令: docker run --help 去查看该命令参数的使用详解.- 使用
docker run 命令启动容器之后,可以通过 docker ps 查看当前正在运行的容器,如果发现当前没有正在运行的容器,那么可以使用 docker ps -a 去查看所有的容器,包含已经关闭的容器. docker exec -it 容器名字 bash :进入该容器内部,每一个容器都相当于是一个Linux环境。docker strop 容器名字|容器ID 可以停掉该容器.docker start 容器名字|容器ID 启动该容器,重新启动这个容器,可能该容器内部的配置文件已经改变.docker restart 容器名字|容器ID 重启该容器.
💡 1.6 DockerFile 非常重要.
参考文档:Dockerfile详解
🔖 二、Nginx.
文档:Nginx中文文档
💡 2.1 什么是Nginx?
Nginx是一款自由的、开源的、高性能的HTTP服务器和反向代理服务器,同时也是一个IMAP、POP3、SMTP代理服务器,Nginx 可以作为一个HTTP服务器进行网站的发布,另外Nginx可以作为反向代理进行负载均衡的实现.
- 正向代理:服务端不知道客户端.
- 反向代理:客户端不知道服务端.
💡 2.2 Nginx 能用来做什么.
- 静态 HTTP 服务器:Nginx 是一个 HTTP 服务器,可以将服务器上的静态文件(HTML、图片)通过HTTP协议展现给客户端.
- 反向代理服务器:反向代理是Nginx做的最多的一件事情,客户端不知道服务端的地址,客户端去请求该Nginx,Nginx通过配置的的路由规则将路由分发到不同的机器上,这个过程客户端是不知道服务端的地址的,只知道Nginx的地址.
- 负载均衡:当网站访问量非常大的时候,可以通过Nginx + 反向代理实现负载均衡 .
💡 2.3 应该怎么用呢?
简单来说就是先配置好路由规则以及域名、监听端口,然后启动Nginx,启动之后,根据HTTP请求去访问Nginx监听的端口,Nginx会根据URI去匹配指定的资源文件.
💡 2.4 Nginx工作原理.
参考文档:Nginx工作原理和优化总结
Nginx采用异步非阻塞的方式来处理网络事件,具体过程:
- 接收请求:每个Worker都是从master进程fork过来的,在master进程建立好需要listen的socket之后,然后带上这个socketfork出多个进程,所有worker进程的socket会在新链接到来时变得可读,每个work进程都可以去accept这个socket,当一个请求到来时,所有可accept的work进程都会感受到通知,为了保证只有一个accept成功,Nginx提供了一个共享锁来保证同一时刻只有一个work进程accept链接。所有worker进程在注册socket读事件前抢accept_mutex,抢到互斥锁的那个进程可以注册socket读事件,在读事件里面调用accept接收该链接.
- 处理请求:当一个worker进程在accept这个链接之后,就开始读取请求、解析请求、处理请求、产生数据之后,再返回给客户端之后才断开链接。
💡 2.5 Nginx 配置详解.
参考博客:最全Nginx 配置文件详解
由于我们这里是用Docker启动的Nginx,所以我们只需要关注Nginx内部配置文件即可,如果不是通过Docker安装的Nginx的话,我们可以通过去Nginx安装目录下面的sbin文件中去启动Nginx.
... #全局块
events { #events块
...
}
http #http块
{
... #http全局块
server #server块
{
... #server全局块
location [PATTERN] #location块
{
...
}
location [PATTERN]
{
...
}
}
server
{
...
}
... #http全局块
}
- 全局快:配置影响Nginx全局的指令,一般有运行Nginx服务器的用户组,Nginx进程PID存放路径、日志存放路基、配置文件引入、允许生成Worker的个数等.
- events快:配置影响Nginx服务器或者与用户的网络连接,有每个进程的最大连接数,选取那种事件驱动模型处理链接请求,是否允许同时接收多个网络连接,开启多个网络序列化等。
- http快:可以嵌套多个server,配置代理、缓存,日志定义等绝大多数功能和第三方模块的配置、链接超时时间、单链接请求数等.
- server快:配置虚拟主机的相关参数,比如域名、编码规则等.
- location块:配置请求路由、以及各种页面处理情况等,比较核心.
#定义Nginx运行的用户和用户组
# 如果出现403可以将user改为root,那是因为本次请求没有权限访问该路径表示的资源.
user root;
#
#nginx进程数,建议设置为等于CPU总核心数.也就是上面的worker的数量.
worker_processes 8;
#
#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
error_log /var/log/nginx/error.log info;
#
#进程文件
pid /var/run/nginx.pid;
#
#一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(系统的值ulimit -n)与nginx进程数相除,但是nginx分配请求并不均匀,所以建议与ulimit -n的值保持一致.
# 不是很懂这个 .
worker_rlimit_nofile 65535;
#
#工作模式与连接数上限
events
{
#参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型.
use epoll;
#单个进程最大连接数(最大连接数=连接数*进程数)
worker_connections 1024; #最大连接数,默认为512
}
#
#设定http服务器
http
{
#charset utf-8; #默认编码
client_header_buffer_size 32k; #上传文件大小限制
keepalive_timeout 65; #连接超时时间,默认为75s,可以在http,server,location块。
# 开启目录列表访问,合适下载服务器,默认关闭.
autoindex on; # 显示目录
autoindex_exact_size on; # 显示文件大小 默认为on,显示出文件的确切大小,单位是bytes 改为off后,显示出文件的大概大小,单位是kB或者MB或者GB
autoindex_localtime on; # 显示文件时间 默认为off,显示的文件时间为GMT时间 改为on后,显示的文件时间为文件的服务器时间
sendfile on; # 开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载.注意:如果图片显示不正常把这个改成off.
tcp_nopush on; # 防止网络阻塞
tcp_nodelay on; # 防止网络阻塞
# 性能优化的模块.
# gzip模块设置
gzip on; #开启gzip压缩输出
gzip_min_length 1k; #允许压缩的页面的最小字节数,页面字节数从header偷得content-length中获取.默认是0,不管页面多大都进行压缩.建议设置成大于1k的字节数,小于1k可能会越压越大
gzip_buffers 4 16k; #表示申请4个单位为16k的内存作为压缩结果流缓存,默认值是申请与原始数据大小相同的内存空间来存储gzip压缩结果
gzip_http_version 1.1; #压缩版本(默认1.1,目前大部分浏览器已经支持gzip解压.前端如果是squid2.5请使用1.0)
gzip_comp_level 2; #压缩等级.1压缩比最小,处理速度快.9压缩比最大,比较消耗cpu资源,处理速度最慢,但是因为压缩比最大,所以包最小,传输速度快
gzip_types text/plain application/x-javascript text/css application/xml;
#压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn.
gzip_vary on;#选项可以让前端的缓存服务器缓存经过gzip压缩的页面.例如:用squid缓存经过nginx压缩的数据
#开启限制IP连接数的时候需要使用
#limit_zone crawler $binary_remote_addr 10m;
##upstream的负载均衡,四种调度算法(下例主讲)##
#虚拟主机的配置
server
{
# 监听端口,如果有请求打到80端口上时,Nginx会处理该请求.
listen 80;
# 域名可以有多个,用空格隔开
server_name 127.0.0.1;
# HTTP 自动跳转 HTTPS
rewrite ^(.*) https://www.baidu.com;
deny 127.0.0.1; #拒绝的ip,表示拒绝该IP进行访问.
allow 172.18.5.54; #允许的ip
# 对需要指定的路径的请求解决跨越问题.
location /指定路径或者正则/{
proxy_pass https://localhost:13580/指定路径或者正则/;
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
在了解了Nginx配置的全局概念之后,我么主要分析下Http模块以及该模块的Server模块.
我们看下面的配置文件,我来主要说一说其主要功能,如果按照下面这样的配置的话,那么当有请求:http://mazhenxin.xyz:18088/index.html 首先,Nginx 匹配到mazhenxin.xyz 之后,将会根据后面的URI进行匹配,Nginx发现 /index.html 和 location /index.html 匹配,那么就会走这个映射规则,然后Nginx就会去服务器找 root+/location-uri 这个路径上的资源文件,至于多不多/ ,Nginx会自动优化,因为我在root 后面加不加 / 都可以匹配到。 因为我们的服务器上在路径root + location-uri 上存在着对应的文件,Nginx 在获取到改文件之后将会解析,解析之后,返回给客户端.
server {
listen 18088;
listen [::]:18088;
server_name mazhenxin.xyz;
# 下面的index不知道是啥意思.
location /index.html {
root /root/nginxmapping/docker;
# index /index.html;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
💡 2.6 upstream 负载均衡详解.
-
负载均衡算法:
- 轮询、权重、IP散列是Nginx原生支持的分配方式
- fail和url_hash为第三方支持的分配方式.
-
使用.
-
轮询是upstream默认的分配方式. -
权重:在server后面直接配置: server 127.0.0.1:8848 weight=1 , 权重的意思就是指定轮询比例,weight和访问成正比率关系,也就是权重越大,访问的次数也越高 . -
ip_hash 方式:每个请求按照访问ip(Nginx的前置服务器或者客户端IP),这样每个用户会固定访问一个后端服务器,可以解决session一致问题. 具体使用如下. upstream test {
ip_hash:
server....
}
🔖 三、动手实战.
实战:Docker安装Nginx实现静态文件映射.
我这里的动手实战的架构图是这样的:
💡 3.1 安装、启动、进入容器内部.
// 下面将会拉取Nginx的镜像.
docker pull nginx
# 查看所有镜像.
docker images
# -p Docker虚拟Linux端口映射到母机端口上.
# -d 该Docker容器在后台启动.
# nginx 是启动该容器时需要的镜像.
docker run --name 容器名字 -p 18088:18088 -d nginx
// docker ps 查看当前正在运行的容器.
// docker ps -a 查看当前所有的容器.
docker ps || docker ps -a
下面是我的运行成功截图.
💡 3.2 修改配置文件.
-
首先我们先修改Nginx的配置文件,因为Nginx容器的启动和安装VIM插件已经学习的差不多了,这里就直接开始修改配置文件. 申明一点:默认的以Docker方式启动的Ngixn容器,其配置文件Nginx.conf是通过include来指向Server模块的配置文件,其在conf.d目录下. 这里我就以Nginx.conf为配置文件来举例说明. // 1. 首先先进入Nginx容器.
docker exec -it nginx bash
// 进入/etc/nginx/下修改文件.
cd /etc/nginx
// 2. 修改Nginx的配置文件如下:
vim nginx.conf
------------Nginx.conf--------------
user root; # 这里需要改成root,否则会出现403错误.
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
// 默认负载均衡是轮询方式.
upstream proxy_html {
server mazhenxin.xyz:8088 max_fails=3 fail_timeout=10s;
server mazhenxin.xyz:8089 max_fails=3 fail_timeout=10s;
}
#gzip on;
server {
listen 18088;
# 通过域名访问.
server_name mazhenxin.xyz;
#charset koi8-r;
#access_log logs/host.access.log main;
# 只要URI是index.html的请求,则全部转到proxy_html上.
# 转发之后的路径是 http://proxy_html/index.html
location /index.html {
proxy_pass http://proxy_html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
------------Nginx.conf--------------
其实这样Nginx网关类似就做好了,然后只需要重新启动以下这个Nginx容器. # 首先退出当前容器.
exit.
# 重启容器。
docker restart 容器名称|容器ID.
现在最上面的Nginx网关层已经做好了,现在来配置HTML服务. -
修改Server HTML-8088 这里我是通过以Nginx为基础镜像外加上一个HTML文件的形式打包成一个镜像,名字称为Linux。具体的Dockerfile如下. FROM nginx
MAINTAINER "zhenxinma@tencent.com"
COPY "./index.html" "/root/dockermapping/"
然后我们可以使用docker build . 来通过当前目录下的Dockerfile来构造一个基于FROM 镜像的镜像. 然后就和上面步骤一样了,启动就OK了. 还是同样的道理,先启动容器、进入容器、安装 vim 插件,修改配置. 上面已经有过步骤,这里就不在赘述.
-
首先先检查下/root/dockermapping/ 目录下是否有index.html 要进行映射的文件. 因为最终请求是要来获取该资源的,所以说这里的资源一定要有. -
然后就是修改配置文件. 修改如下. # 这里是通过包含配置文件的形式来启动配置文件的.
# 先来看下nginx.conf配置文件.
# 这里的user一定要改为root,否则请求可能没有权限去访问目标资源.
user root;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
# 这里说明当前配置文件包含了哪些配置文件.
include /etc/nginx/conf.d/*.conf;
}
# 全局配置文件。
server {
listen 8088;
listen [::]:8088;
server_name mazhenxin.xyz;
location /index.html {
root /root/dockermapping;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
当有请求从18088Nginx服务过来之后,其会根据URI来取访问目标资源. -
修改Server HTML-8089 配置文件. 同理,依然利用Nginx为基础镜像,将HTML打包成一个镜像. 具体和上面类似,这里就不在啰嗦了直接上修改好的配置文件即可.
- 我们先看下
index.html 文件是否存在. # 下面的命令是在进入容器之后执行的.
root@a217d3dd7e75:/# cd /root/dockermapping/
root@a217d3dd7e75:~/dockermapping# ls
index.html
root@a217d3dd7e75:~/dockermapping# cat index.html
<b>
Hello Wrod Docker Nginx Mapping to Html.-8089
</b>
root@a217d3dd7e75:~/dockermapping#
通过上面可以看到,index.html 是存在的,且页面内容是8089的.
- 修改Nginx的配置文件.
root@a217d3dd7e75:/etc/nginx/conf.d# cat default.conf
server {
listen 8089;
listen [::]:8089;
# 配置以域名的形式访问.
server_name mazhenxin.xyz;
location / {
root /root/dockermapping;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
重新启动加载配置文件,这里一定要将修改过配置文件的容器重新启动。
来看最后结果:
第一次:
第二次:
OK,大功告成!
欢迎关注下我的公众号(同掘金):小马教你写Bug 一起学习 互相成长!
|