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一键部署,这里展示我的配置文件:
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官网文档
码字不易,希望我的文档对你的学习有帮助,如有读者发现我有错或者哪些地方不足,还麻烦指出;如果我上面发的连接失效了,读者们也可以自行去百度。
感谢浏览!