環境介紹
docker的好處有很多,這里就不多說了,win10上安裝docker要求是專業版的win10,而我們一般買的是家庭版的,家庭版可以通過激活碼升級成專業版,至于激活碼,讀者們可以去某寶買,不貴。當然win10家庭版上也可以通過一些復雜的配置讓其能跑docker,這個可以自行百度。
我這里假定讀者們已經在win10中安裝并配置好docker,這里我就簡單的說一下我的docker配置吧。
這里shared Drivers表示配置共享區,我這里讓d盤的文件可以被共享到docker容器中。
在Daemon中配置docker下載的源:
docker的配置大致就這么多,這個你們在搜安裝教程的時候應該都有介紹。
在具體配置docker前我先簡單介紹下個人理解的docker的作用機制和我開發過程中的常用命令,如果你已經比較熟悉docker可以跳過這部分的介紹。
docker分為容器和鏡像,可以相互轉化,一般容器基于一個鏡像創建,容器配置好內部環境后可以打包成鏡像,然后push到云端,其他有docker環境的機器可以直接pull然后就可以創建容器運行了。具體的命令大家可以參考官網,菜鳥教程或者一些博客,部分學習鏈接我后面會貼出來。
我個人的理解是每個容器相當于一個“獨立”的簡易linux環境,有點像虛擬機,說它是獨立的但又不像,因為我在一個容器中安裝ping指令,在其他容器中也可以用ping,但不同容器的服務確實可以指定同一個端口,就好像不在同一臺機器上。既然是獨立的環境,那么你項目中用的很多ip地址就可能得換一換了,這就體現在數據庫的連接和nginx的反向代理上。比如我數據庫分為兩個容器,一個由redis鏡像生成,一個由mongodb生成,而我nodejs應用要連接這兩個容器的話就得指定這兩個容器所在的ip,而不是localhost,這個時候的localhost指向的容器,而非宿主機的localhost,這個得理解。
再說一說我nginx容器的反向代理,剛開始我以為只需要反向代理我容器的ip就行了,可是我試了很多次后就是失敗。nginx映射到宿主機的端口就是不能訪問我的項目,仔細想了想,nginx的代理和我vue開發中的代理跨域有幾分相像,就是把請求的它的轉到請求他代理的端口上,如果連他代理的端口都不能訪問項目,那當然無法訪問,帶著疑問,我把我node的容器的ip加端口3000輸入在瀏覽器上面的地址上,確實無法訪問,這是docker內部的ip,它內部通過建立端口映射到宿主機后才可以在宿主機上用localhost或者ipv4的地址加端口訪問,所以我最終還是把我的node項目暴露出來,建立端口映射,比如是3001:3000,那么我們輸入localhost:3001就相當于訪問我node容器的3000了,結果果然如我猜想,項目能訪問,接下來我再將nginx的代理轉到宿主機的ipv4上,建立端口映射80:80,那么我們訪問localhost時,這個訪問會從默認端口80進去nginx容器端口80,被nginx轉到宿主機ipv4下的3001端口,再從這個端口進入node容器的3000端口,就達到訪問我們項目的目的了。
前面廢話這么多都是為了我接下來的配置做鋪墊,不多說了,直接上代碼吧。
docker-compose.yml
我用的docker-compose一鍵部署,這里展示我的配置文件:
docker-compose.yml
version: '3.7'
services:
mongodbservice:
image: mongo:3.2 #鏡像
container_name: mongodbservice #容器名
deploy: #這個配置到好像會報警告,說會忽視,不礙事,也可以不加
restart_policy:
condition: on-failure #none on-failure any
delay: 5s
max_attempts: 3
window: 60s #deploy配置到這里結束
volumes: #文件映射
- ./mongo3.2/mongod.conf.orig:/etc/mongod.conf.orig #自定義mongodb配置文件
# - ./mongo3.2/mongodata/db:/data/db #映射數據庫文件到宿主機,win10下開啟會報錯,但在linux中一般要開啟,不把數據保存在容器中
ports: #映射端口到宿主機,方便遠程連接和可視化工具連接查看
- 27018:27017
# environment: #mongodb連接的用戶名和密碼,加上后代碼中可能也得加
# MONGO_INITDB_ROOT_USERNAME: root
# MONGO_INITDB_ROOT_PASSWORD: 123456
# command: mongod --dbpath /data/db --logpath /data/log/dblog.log --auth #command表示容器啟動后要執行的命令
networks: #加入網絡組
webapp-network: #指定加入名字為webapp-network的網絡環境
ipv4_address: 172.23.0.6 #給容器分配靜態ip
aliases: #給該ipv4配置別名
- mongodbservice
redisService:
image: redis:3.2
container_name: redisService
deploy: #用docker-compose -f可選 --compatibility up 運行
restart_policy:
condition: on-failure #none on-failure any
delay: 5s
max_attempts: 3
window: 30s
ports:
- 6380:6379
volumes:
- ./redis3.2/redisdata/data:/data
- ./redis3.2/redis.conf:/etc/redis/redis.conf
command: redis-server /etc/redis/redis.conf #通過我自定義的配置文件啟動redis
networks:
webapp-network:
ipv4_address: 172.23.0.2
aliases:
- redisService
nginxService:
image: nginx
container_name: nginxService
deploy:
restart_policy:
condition: on-failure #none on-failure any
delay: 3s
max_attempts: 3
window: 30s
ports:
- 80:80
- 443:443
volumes:
- ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/https:/etc/nginx/https
depends_on: #依賴nodeService服務的啟動,控制啟動先后順序
- nodeService
extra_hosts: #將ip寫進host中方便項目代碼訪問
- "myappService:宿主機的ipv4地址" #這里應該是宿主機ipv4,win10可以在powershell或cmd中通過ipconfig命令查看
networks:
webapp-network:
ipv4_address: 172.23.0.3
nodeService:
image: node
container_name: nodeService
depends_on:
- mongodbservice
- redisService
ports:
- 3000:3000
# links: #將要淘汰
# - mongodbservice
# - redisService
working_dir: /usr/local/app #指定工作目錄
volumes:
- ./nodejs/app:/usr/local/app
command: node server/myapp.js #啟動node服務,在linux上可用pm2啟動
extra_hosts: #給/etc/hosts加dns映射,這個配置比較重要
- "redisService:172.23.0.2"
- "mongodbservice:172.23.0.6"
- "musicService:172.23.0.5"
networks:
webapp-network:
ipv4_address: 172.23.0.4
nodeServicemusic:
image: node
container_name: nodeServicemusic
# ports:
# - 3002:3000
working_dir: /usr/local/app
volumes:
- ./nodejs/app:/usr/local/app
command: node NeteaseCloudMusicApi/app.js #網易云的音樂服務
networks:
webapp-network:
ipv4_address: 172.23.0.5
networks:
webapp-network: #使用或新建network
name: webapp-network #network名字
driver: bridge #單機情況為bridge,多機器為overlay
ipam:
driver: default
config:
- subnet: "172.23.0.0/16" #給network指定基本ip,同時還會有一個Gateway占用172.23.0.1這個ip
上面雖然寫了注釋,但我這里還是嘮叨幾句,我百度他人的部署博客時,別人配置所在的環境基本上都是在linux中,但我在win10本地上學習docker時,用他們的配置,項目就是連不上數據庫,報錯說ip找不到,可是我在容器里下載ping后確實可以根據服務名ping通同一network下的其他容器,因為我用的npm包,比如mongoose連接數據庫,redis包連接redis,后才我就猜是host的問題,這些包底層的代碼應該是去找host文件的ip映射,通過docker exec -it 容器名/id bash 進入容器交互式環境,進入環境后才可以ping其他服務或者ip,補充一下,我在交互式環境下通過命令 cat /etc/hosts 發現ip映射并沒有同一network其他容器服務名的ip映射,倒是有自己的容器id和容器ip的映射。這就證明了我的猜想。win10下,為了方便在代碼里設置ip,我需要主動給容器分配ip,并在node容器中配置其他容器的host映射。
我這里給容器分配ip時,因為他們在同一network下,為了防止可能出現的異常情況,我給每個容器分配的ip是network的ip的子ip,我上面配置的最下面有我webapp-network的ip配置,172.23.0.0/16 這個,其中后面的16表示用了16位表示網絡號,這里有一點計算機網絡基礎的應該能看懂,好吧我就是跟著人家自己的network配的ip,安裝下載好后的docker可以在powershell中通過命令docker network ls 查看有哪些network,默認有三個network,其中一個的name叫brige,通過docker network inspect brige 可以查看brige網絡的配置信息。你會發現這個默認網絡的ip是172.17.0.0/16,還有個172.17.0.1也被占用了,這個具體有什么用我暫時沒理解,不過這跟我目前的項目配置無多大干系。在測試的過程中我發現我新建的network被自動分配了這樣的ip“172.18.0.0/16”,“172.19.0.0/16”有點像mysql里的數據id自增,而通過inspect查看這些network中的容器數組配置,我發現,容器自動分配的ip像這樣“172.18.0.2”,“172.18.0.3”,有點感覺了!這些容器的ip就像networkip下的子網,于是就有了我上面的配置。為了方便瀏覽,我這里再次截下圖:
分配好ip后就可以直接在node應用容器的host中加入這些映射,像這樣:
這個映射就跟localhost 127.0.0.1 一個道理。在node應用代碼中就可以直接通過前面這個別名訪問映射ip對應的容器中的服務,像這樣:
這里可能有讀者注意到我配置文件中的mongodbservice中的s是小寫,而我這里的代碼中的是大寫,那是因為在調試過程中我發現報錯信息里的mongodbservice是小寫,于是我就推測mongoose包給我自動轉成小寫了,為了避免不必要的錯誤,我配置host的時候改成了小寫。這里第二行注釋的代碼表示鑒權連接數據庫。vuedb2manager表示用戶名,123456表示密碼。
同理redis的連接也用映射的host名:
具體的連接方法和鑒權讀者們可以自行去百度或者去npm官方看該npm包的使用文檔。下面是我的配置目錄結構:
其中nodejs/app中的neteasecloudmusicapi文件夾是網易云音樂接口的nodejs版,我項目里有掉這個服務的接口,所以這里我新建了一個容器去跑這個網易云的服務,下面是我myapp.js中的部分代碼:
這里的musicService是我上面配置的host映射。這個網易云音樂的容器就沒必要與宿主機建立端口映射了,所以我把上面這塊的配置注釋了。
我再貼一個nginx的代理映射,這個也比較重要,我nginx代理的是宿主機的ip,至于為什么要代理宿主機,而不是直接代理node容器的ip,沒有那么多為什么,我代理我容器的ip就是訪問不了我的項目,可能得在容器內把對應端口打開?還是其他原因?我個人的理解已經在最開始說明,這里就不再繼續闡述。
nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
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;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
#include /etc/nginx/conf.d/*.conf;
upstream vuemongo {
server myappService:3000;
}
server {
listen 80;
server_name localhost;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://vuemongo;
# root D:\project\vueweek\vuemongo6.1\client\dist;
# index index.html index.htm;
}
}
}
我這里把他默認引入的include注釋掉了,它這里默認的一些配置影響到我下面自定義的配置了,所以我就給注銷了,我這里沒有配置錯誤頁面404,50x之類的頁面,所以嚴格來說我這樣配置不是合格的,但是配置我們的項目足夠了。其中myappService是我nginx容器中配置的這個:
可能你會問我,為什么你不放mongodb和redis的配置,首先,它的配置文件代碼太多,而且容器中的配置和非容器的配置可能也有些不同,我這里的處理方法是先用這些下載好的鏡像啟動一個容器,然后用命令docker cp 容器id或容器名:/etc/nginx/nginx.conf ./nginx/conf把容器內的文件拷到外部環境的相對目錄下,反過來則是把外部環境的文件拷到容器內,像這樣,docker cp ./nginx/conf/nginx.conf 容器id或容器名:/etc/nginx/ 注意這里最后面有斜杠才表示拷貝到該文件夾下,否則表示拷貝到etc并且重命名為nginx。
mongodb和redis要用自定義配置的話也是同理,先拷貝一份出來,再在新建的容器中建立映射。
我的docker中的mongodb配置:
主要是注銷bindip或者改成0.0.0.0,后面的auth表示鑒權連接,開了之后每次連接就得用對應數據庫或者mongodb管理員的用戶名和密碼。
redis的配置也是注銷這個bindip然后加個“requirepass 你的連接密碼”,具體的配置讀者可以去百度。
這些配置整完后就可以在這個docker-compose.yml配置所在的文件下的空白處按住shift鍵右擊鼠標在出現的菜單列表中選擇powershell打開命令行,輸入docker-compose up,docker會在當前命令所在目錄和它的父級目錄下去找默認的docker-compose.yml配置文件。在up后面加個-d表示后臺運行,但是那樣你就看不到報錯信息了,所以調試過程我們一般不加-d。
現在你想刪除剛剛用那個配置文件新建的容器和network,你可以直接使用命令docker-compose down,它會自動把用默認配置生成的這些環境卸載掉,便于下一次調試。
你可能注意到我那個文件夾下除了docker-compose.yml文件還有其他.yml后綴的文件。你可以用docker-compose -f yourfilepath up和docker-compose -f filepath down來指定配置文件調試。給個例子,我用我當前文件夾下的test.yml配置文件啟動容器啊之類的:docker-compose -f ./test.yml up,完事兒我想卸載剛剛新建的環境:docker-compose -f ./test.yml down
這里放幾個我學習過程中用到的參考鏈接:
docker菜鳥教程
redis遠程連接配置
docker下安裝mongodb并創建用戶
docker官網文檔
碼字不易,希望我的文檔對你的學習有幫助,如有讀者發現我有錯或者哪些地方不足,還麻煩指出;如果我上面發的連接失效了,讀者們也可以自行去百度。
感謝瀏覽!