win10下docker部署nginx+node+mongodb+redis学习

环境介绍

docker的好处有很多,这里就不多说了,win10上安装docker要求是专业版的win10,而我们一般买的是家庭版的,家庭版可以通过激活码升级成专业版,至于激活码,读者们可以去某宝买,不贵。当然win10家庭版上也可以通过一些复杂的配置让其能跑docker,这个可以自行百度。


我这里假定读者们已经在win10中安装并配置好docker,这里我就简单的说一下我的docker配置吧。

这里shared Drivers表示配置共享区,我这里让d盘的文件可以被共享到docker容器中。

win10下docker部署nginx+node+mongodb+redis学习_第1张图片

在Daemon中配置docker下载的源:

win10下docker部署nginx+node+mongodb+redis学习_第2张图片

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下的子网,于是就有了我上面的配置。为了方便浏览,我这里再次截下图:
win10下docker部署nginx+node+mongodb+redis学习_第3张图片
win10下docker部署nginx+node+mongodb+redis学习_第4张图片
分配好ip后就可以直接在node应用容器的host中加入这些映射,像这样:
win10下docker部署nginx+node+mongodb+redis学习_第5张图片
这个映射就跟localhost 127.0.0.1 一个道理。在node应用代码中就可以直接通过前面这个别名访问映射ip对应的容器中的服务,像这样:
image.png
这里可能有读者注意到我配置文件中的mongodbservice中的s是小写,而我这里的代码中的是大写,那是因为在调试过程中我发现报错信息里的mongodbservice是小写,于是我就推测mongoose包给我自动转成小写了,为了避免不必要的错误,我配置host的时候改成了小写。这里第二行注释的代码表示鉴权连接数据库。vuedb2manager表示用户名,123456表示密码。
同理redis的连接也用映射的host名:
image.png
具体的连接方法和鉴权读者们可以自行去百度或者去npm官方看该npm包的使用文档。下面是我的配置目录结构:
win10下docker部署nginx+node+mongodb+redis学习_第6张图片
win10下docker部署nginx+node+mongodb+redis学习_第7张图片image.pngwin10下docker部署nginx+node+mongodb+redis学习_第8张图片win10下docker部署nginx+node+mongodb+redis学习_第9张图片

其中nodejs/app中的neteasecloudmusicapi文件夹是网易云音乐接口的nodejs版,我项目里有掉这个服务的接口,所以这里我新建了一个容器去跑这个网易云的服务,下面是我myapp.js中的部分代码:

win10下docker部署nginx+node+mongodb+redis学习_第10张图片

这里的musicService是我上面配置的host映射。这个网易云音乐的容器就没必要与宿主机建立端口映射了,所以我把上面这块的配置注释了。
win10下docker部署nginx+node+mongodb+redis学习_第11张图片

我在贴一个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容器中配置的这个:
win10下docker部署nginx+node+mongodb+redis学习_第12张图片

可能你会问我,为什么你不放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配置:
win10下docker部署nginx+node+mongodb+redis学习_第13张图片
主要是注销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 updocker-compose -f filepath down来指定配置文件调试。给个例子,我用我当前文件夹下的test.yml配置文件启动容器啊之类的:docker-compose -f ./test.yml up,完事儿我想卸载刚刚新建的环境:docker-compose -f ./test.yml down

这里放几个我学习过程中用到的参考链接:
docker菜鸟教程
redis远程连接配置
docker下安装mongodb并创建用户
docker官网文档

码字不易,希望我的文档对你的学习有帮助,如有读者发现我有错或者哪些地方不足,还麻烦指出;如果我上面发的连接失效了,读者们也可以自行去百度。

感谢浏览!

你可能感兴趣的:(经验,docker部署node应用)