前言
距離上一篇文章已經很長時間,近期實在事情太多了,也沒來得及繼續更新一些新的內容。現在開發使用的工作實在太多了,小編實在忍受不了windows那樣卡機的狀態,於是最近換了一個mac電腦,雖然做開發已經很長時間了,之前一直沒有用過mac,不過使用過后才發現mac實在是windows無法媲美的,當然了mac的價格也是相當的昂貴啊....
好了廢話不多說了,現在讓我們開始正題,首先讓我們現在mac下如何安裝docker
docker安裝
Docker 官網:http://www.docker.com
Github Docker 源碼:https://github.com/docker/docker
docker相關介紹,這里就不多說了啊,沒學習過的同學可以看下上面的2個網址學習下。
安裝命令
brew cask install docker
怎么樣是不是很方便,在mac環境下只需要執行上面一句話就可以搞定docker的安裝了,當然了這里的前提是你已經安裝了Homebrew(macOS 缺失的軟件包的管理器),不要問我Homebrew 是什么了,這里我把教程附上,有興趣的同學自己看下把,mac下使用brew命令還是相當的方便的
https://brew.sh/index_zh-cn 中文官方網站
按上述步驟安裝完成后,執行biew -v 如果出現下面結果及說明安裝成功
Homebrew 1.8.6 Homebrew/homebrew-core (git revision b22b69a; last commit 2019-01-05) Homebrew/homebrew-cask (git revision 382e0; last commit 2019-04-03)
這里順便附下其他系統的docker安裝把
Ubuntu Docker 安裝
CentOS Docker 安裝 (親試)
Windows Docker 安裝 (個人建議進來不要使用windows,裝個虛擬機都可以)
MacOS Docker 安裝 (親試)
nginx安裝
讓我們先來拉取下nginx的鏡像吧,這里我采用網易雲的鏡像,官方的鏡像國內打開是在太慢了
docker pull hub.c.163.com/library/nginx:latest
拉取成功后讓我們先看下本地的鏡像
docker images
通過上門的命令就可以看到nginx的鏡像已經被我們拉取過來了
然后我們就可以先啟動一下這個nginx了,在這里我們使用docker run命令來運行,不熟悉的同學可以通過docker run --help 來查看幫助文檔
-d :分離模式: 在后台運行
docker run -d hub.c.163.com/library/nginx
讓我們來檢查下nginx進程
jack-4:~ jack$ docker run -d hub.c.163.com/library/nginx 2d839f976fa88513854f4540d9c8f49ff1110640570bd2bd8c51471491f8a85d jack-4:~ jack$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2d839f976fa8 hub.c.163.com/library/nginx "nginx -g 'daemon of…" 3 seconds ago Up 2 seconds 80/tcp affectionate_elion jack-4:~ jack$
這里我們就能看到我們的nginx已經起來了,但是由於docker是虛擬了一個容器出來,所以我們現在還不能訪問nginx,接下來我們通過把本地端口映射到虛擬容器的nginx端口上就可以訪問nginx了
docker run -d -p 8080:80 hub.c.163.com/library/nginx
運行改命令后,命令行會輸出當前容器的id
34453d528a8c9adbb4d67959053d5fb2ae38221b81c7519744f184f7fd0d5330
下面我們會用到他,這里稍微標記下
接下來我們通過訪問:http://127.0.0.1:8080/ 就可以看到我們熟悉的nginx歡迎界面了。
好了到此為止,一個nginx就通過docker的方式在我們本機器啟動起來了,而且也可以正常訪問了,使用過nginx的同學都知道這肯定不滿足我們的要求啊,我還要修改nginx.conf呢,怎么辦呢, 怎么進入docker容器重啟nginx呢... 等等一系列的問題還沒解決呢,下面讓我們繼續來好好地搞一搞吧。
Nginx實戰
上面我們通過將本地8080端口映射到docker容器的80端口上實現了nginx的訪問,當然我們也可以通過隨機端口的映射方式
docker run -d -P hub.c.163.com/library/nginx
部署nginx 項目並修改配置文件
一般情況下docker啟動時進行配置,只要把配置文件的目錄掛載出來就可以,但是nginx卻是先加載一個主配置文件nginx.conf,在nginx.conf里再加載conf.d目錄下的子配置文件(一般最少一個default.conf文件)。
docker拉取下來的nginx配置文件路徑
日志文件位置:/var/log/nginx
配置文件位置: /etc/nginx
資源存放的位置: /usr/share/nginx/html
接下來我們現在本地創建對應的目錄,並將目錄掛在到docker容器的nginx上(可以看后面的采坑實力如何拷貝nginx.conf和conf.d中的文件)
/Users/jack/Documents/docker/nginx/log
/Users/jack/Documents/docker/nginx/html
/Users/jack/Documents/docker/nginx/conf/nginx.conf 注意:這是文件
/Users/jack/Documents/docker/nginx/conf/conf.d 注意:這是文件夾
本地掛載目錄創建完畢后讓我們來重新看下我們的nginx啟動命令,這次增加了很多東西
# 1. 第一個“-v”,是nginx日志位置,把ngixn日志放到掛載到的目錄下 # 2. 第二個“-v”,是項目位置,把項目放到掛載到的目錄下即可 # 3. 第三個“-v”,是掛載的主配置文件"nginx.conf",注意"nginx.conf"文件內有一行 # "include /etc/nginx/conf.d/*.conf;" , # 這個include指向了子配置文件的路徑,此處注意include后所跟的路徑一定不能出錯 # 4. 第四個“-v”,把docker內子配置文件的路徑也掛載了出來,注意要與 “2.” 中include指向路徑一致 # 5. nginx.conf是掛載了一個文件(docker是不推薦這樣用的),conf.d掛載的是一個目錄
docker run \ --name myNginx \ -d -p 8080:80 \ -v /Users/jack/Documents/docker/nginx/log/:/var/log/nginx \ -v /Users/jack/Documents/docker/nginx/html:/usr/share/nginx/html \ -v /Users/jack/Documents/docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \ -v /Users/jack/Documents/docker/nginx/conf/conf.d:/etc/nginx/conf.d \ hub.c.163.com/library/nginx
這次命令我增加了一個--name屬性,給我們的docker容器新增加了一個名字,后面可以通過myNginx來重啟或者關閉容器
啟動成功后我們再通過命令來看下docker啟動情況和掛載情況
jack-4:~ jack$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 48b10d0f0fdb hub.c.163.com/library/nginx "nginx -g 'daemon of…" 30 seconds ago Up 29 seconds 0.0.0.0:8080->80/tcp myNginx
這里可以看到8080端口已經映射成功了,繼續執行命令查看掛載情況
docker inspect myNginx | grep Mounts -A 200
"Mounts": [ { "Type": "bind", "Source": "/Users/jack/Documents/docker/nginx/conf/conf.d", "Destination": "/etc/nginx/conf.d", "Mode": "", "RW": true, "Propagation": "rprivate" }, { "Type": "bind", "Source": "/Users/jack/Documents/docker/nginx/log", "Destination": "/var/log/nginx", "Mode": "", "RW": true, "Propagation": "rprivate" }, { "Type": "bind", "Source": "/Users/jack/Documents/docker/nginx/html", "Destination": "/usr/share/nginx/html", "Mode": "", "RW": true, "Propagation": "rprivate" }, { "Type": "bind", "Source": "/Users/jack/Documents/docker/nginx/conf/nginx.conf", "Destination": "/etc/nginx/nginx.conf", "Mode": "ro", "RW": false, "Propagation": "rprivate" } ], "Config": { "Hostname": "48b10d0f0fdb", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "80/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "NGINX_VERSION=1.13.0-1~stretch", "NJS_VERSION=1.13.0.0.1.10-1~stretch" ], "Cmd": [ "nginx", "-g", "daemon off;" ], "ArgsEscaped": true, "Image": "hub.c.163.com/library/nginx", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": {}, "StopSignal": "SIGQUIT" }, "NetworkSettings": { "Bridge": "", "SandboxID": "d0f15aa6836d41199d6c6ab2a13a77df69c9fe336e7721127b24ea626edc2ea5", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": { "80/tcp": [ { "HostIp": "0.0.0.0", "HostPort": "8080" } ] }, "SandboxKey": "/var/run/docker/netns/d0f15aa6836d", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "6d937b1e1b72da739281adf9c6727ee618beb203660e168fbffd0fc6e1b6b8f6", "Gateway": "172.17.0.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "MacAddress": "02:42:ac:11:00:02", "Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "b9eff4ad3b8cdd9dc1e6d16eaecedabfbeb4ae9f89be23c79a23569089e5a99b", "EndpointID": "6d937b1e1b72da739281adf9c6727ee618beb203660e168fbffd0fc6e1b6b8f6", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:02", "DriverOpts": null } } } } ]
這里可以看到nginx的掛載情況和端口映射情況,到這里為止我們就可以隨意的修改我們的nginx了,在本地的html文件夾和conf.d中任意增加代碼和配置,在docker容器中重新啟動nginx就可以了,好了,下面讓我們繼續docker的一下常用操作:
docker attach 容器名或者容器ID bash # 進入容器的命令行(退出容器后容器會停止)
docker exec -it 容器名或者容器ID bash # 進入容器的命令行
docker exec -it 34453 bash
docker exec -it myNginx bash
which nginx
直接返回了nginx在容器中的路徑,那我們修改完配置后如何重啟nginx呢,其實命令還是一樣的,直接執行
nginx -s reload
就可以重啟成功了
查看容器日志
docker logs -f 容器名稱
到現在為止,nginx的安裝,啟動,進入容器內部重啟就都說完了,接下來我們進入最后的一部分,如何退出、重啟docker容器呢
docker stop 容器id/名稱 # 停止容器 docker rm 容器id/名稱 # 刪除容器 docker restart 容器id/名稱 #重啟容器
exit #退出docker容器
netstat -na|grep 8080 # 本地查看8080端口映射情況
采坑實例
博主在一開始配置nginx的時候,並沒有拷貝nginx.conf和conf.d里面的default.conf文件到本地的掛載目錄,而是新創建了二個文件,直接拷貝nginx文件里面的代碼過來的,結果每次重啟nginx后總會包一個錯誤
. unexpected "{" in /etc/nginx/nginx.conf:1
經過反復查看核驗文件內容均沒有發現有什么異常,這個問題困擾了1天的時間,突然想到會不會是文件編碼的問題,於是通過拷貝的方式拷貝這兩個文件到本地目錄,重啟Nginx后解決,下面附上拷貝的代碼
docker cp myNginx:/etc/nginx/nginx.conf /Users/jack/Documents/docker/nginx/conf/nginx.conf docker cp myNginx:/etc/nginx/conf.d/default.conf /Users/jack/Documents/docker/nginx/conf/conf.d/default.conf
好了,到這里本片文章就徹底結束了,有問題的小伙伴可以給我留言評論。下面我附上我本地的兩個文件代碼
nginx.conf和default.conf
nginx.conf
user nginx; worker_processes 1; worker_rlimit_nofile 65535; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { use epoll; worker_connections 65535; } 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; charset UTF-8; client_max_body_size 300m; sendfile on; #tcp_nopush on; keepalive_timeout 60; gzip on; include /etc/nginx/conf.d/*.conf; }
default.conf
#upstream sisafezuul { # server 192.168.11.4:8080 max_fails=2 fail_timeout=30s; #} #server { # listen 80; # server_name sietsafe.ecej.com; # client_max_body_size 10M; # rewrite ^(.*)$ https://$host$1 permanent; #} #server { # listen 443 ssl; # server_name etsafeadm.guizhou001.cn; # # ssl_certificate cert/etsafeadm.guizhou001.cn.pem; # ssl_certificate_key cert/etsafeadm.guizhou001.cn.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location ~* /openapi { # proxy_pass http://127.0.0.1:9999; # } # location ~* /safety { # proxy_pass http://127.0.0.1:9999; # } # location / { # root website/console; # index index.html; # } # } server { listen 80; server_name localhost; location /rewrite { rewrite "/" http://127.0.0.1:8888/ break; } location /mickey.html { root /usr/share/nginx/html/mickey; } #location ~* \.(html|htm|gif|jpg|jpeg|bmp|png|ico|js|css|eot|svg|ttf|woff)$ { # index index.htm index.html; # root /data/nfsdata/website/official; #} #location / { # index index.htm index.html index.jsp; # proxy_pass http://sisafezuul; #} location / { root /usr/share/nginx/html; index index.html index.htm; } }
(附加)nginx location配置詳細
語法規則: location [=|~|~*|^~] /uri/ { … }
-
=
開頭表示精確匹配 -
^~
開頭表示uri以某個常規字符串開頭,理解為匹配 url路徑即可。nginx不對url做編碼,因此請求為/static/20%/aa,可以被規則^~ /static/ /aa匹配到(注意是空格)。 -
~
開頭表示區分大小寫的正則匹配 -
~*
開頭表示不區分大小寫的正則匹配 -
!~
和!~*
分別為區分大小寫不匹配及不區分大小寫不匹配 的正則 -
/
通用匹配,任何請求都會匹配到。
多個location配置的情況下匹配順序為(參考資料而來,還未實際驗證,試試就知道了,不必拘泥,僅供參考):
首先匹配 =,其次匹配^~, 其次是按文件中順序的正則匹配,最后是交給 / 通用匹配。當有匹配成功時候,停止匹配,按當前匹配規則處理請求。
例子,有如下匹配規則:
location = / { #規則A } location = /login { #規則B } location ^~ /static/ { #規則C } location ~ \.(gif|jpg|png|js|css)$ { #規則D } location ~* \.png$ { #規則E } location !~ \.xhtml$ { #規則F } location !~* \.xhtml$ { #規則G } location / { #規則H }
那么產生的效果如下:
訪問根目錄/, 比如http://localhost/ 將匹配規則A
訪問 http://localhost/login 將匹配規則B,http://localhost/register 則匹配規則H
訪問 http://localhost/static/a.html 將匹配規則C
訪問 http://localhost/a.gif, http://localhost/b.jpg 將匹配規則D和規則E,但是規則D順序優先,規則E不起作用, 而 http://localhost/static/c.png 則優先匹配到 規則C
訪問 http://localhost/a.PNG 則匹配規則E, 而不會匹配規則D,因為規則E不區分大小寫。
訪問 http://localhost/a.xhtml 不會匹配規則F和規則G,http://localhost/a.XHTML不會匹配規則G,因為不區分大小寫。規則F,規則G屬於排除法,符合匹配規則但是不會匹配到,所以想想看實際應用中哪里會用到。
訪問 http://localhost/category/id/1111 則最終匹配到規則H,因為以上規則都不匹配,這個時候應該是nginx轉發請求給后端應用服務器,比如FastCGI(php),tomcat(jsp),nginx作為方向代理服務器存在。
所以實際使用中,個人覺得至少有三個匹配規則定義,如下:
nginx的其他配置信息介紹
三、ReWrite語法
last
– 基本上都用這個Flag。break
– 中止Rewirte,不在繼續匹配redirect
– 返回臨時重定向的HTTP狀態302permanent
– 返回永久重定向的HTTP狀態301
1、下面是可以用來判斷的表達式:
-f
和!-f
用來判斷是否存在文件-d
和!-d
用來判斷是否存在目錄-e
和!-e
用來判斷是否存在文件或目錄-x
和!-x
用來判斷文件是否可執行
2、下面是可以用作判斷的全局變量
例:http://localhost:88/test1/test2/test.php
$host:localhost $server_port:88 $request_uri:http://localhost:88/test1/test2/test.php $document_uri:/test1/test2/test.php $document_root:D:\nginx/html $request_filename:D:\nginx/html/test1/test2/test.php
四、Redirect語法
server { listen 80; server_name start.igrow.cn; index index.html index.php; root html; if ($http_host !~ "^star\.igrow\.cn$" { rewrite ^(.*) http://star.igrow.cn$1 redirect; } }
五、防盜鏈
location ~* \.(gif|jpg|swf)$ { valid_referers none blocked start.igrow.cn sta.igrow.cn; if ($invalid_referer) { rewrite ^/ http://$host/logo.png; } }
六、根據文件類型設置過期時間
location ~* \.(js|css|jpg|jpeg|gif|png|swf)$ { if (-f $request_filename) { expires 1h; break; } }
七、禁止訪問某個目錄
location ~* \.(txt|doc)${ root /data/www/wwwroot/linuxtone/test; deny all; }
附:一些可用的全局變量
$args $content_length $content_type $document_root $document_uri $host $http_user_agent $http_cookie $limit_rate $request_body_file $request_method $remote_addr $remote_port $remote_user $request_filename $request_uri $query