• [docker] 网络连接


    [docker] 网络连接

    使用 docker 容器会遇到下面 3 种情况:

    1. 容器与万维网之间的交流

      默认情况下是允许的

    2. 从容器到本机的交流

      假设有一些服务运行在本机,如数据库,而 docker 需要和本机进行交流去获取数据

      这个实现需要配置

    3. 容器与容器之间的交流

      这个是比较常见的用法了,同样需要配置

    项目配置

    配置一个 node 项目去运行一下项目

    代码

    app.js:

    const express = require("express");
    const bodyParser = require("body-parser");
    const axios = require("axios").default;
    const mongoose = require("mongoose");
    
    const Favorite = require("./models/favorite");
    
    const app = express();
    
    app.use(bodyParser.json());
    
    app.get("/favorites", async (req, res) => {
      const favorites = await Favorite.find();
      res.status(200).json({
        favorites: favorites,
      });
    });
    
    app.post("/favorites", async (req, res) => {
      const favName = req.body.name;
      const favType = req.body.type;
      const favUrl = req.body.url;
    
      try {
        if (favType !== "movie" && favType !== "character") {
          throw new Error('"type" should be "movie" or "character"!');
        }
        const existingFav = await Favorite.findOne({ name: favName });
        if (existingFav) {
          throw new Error("Favorite exists already!");
        }
      } catch (error) {
        return res.status(500).json({ message: error.message });
      }
    
      const favorite = new Favorite({
        name: favName,
        type: favType,
        url: favUrl,
      });
    
      try {
        await favorite.save();
        res
          .status(201)
          .json({ message: "Favorite saved!", favorite: favorite.toObject() });
      } catch (error) {
        res.status(500).json({ message: "Something went wrong." });
      }
    });
    
    app.get("/movies", async (req, res) => {
      try {
        const response = await axios.get("https://swapi.dev/api/films");
        res.status(200).json({ movies: response.data });
      } catch (error) {
        res.status(500).json({ message: "Something went wrong." });
      }
    });
    
    app.get("/people", async (req, res) => {
      try {
        const response = await axios.get("https://swapi.dev/api/people");
        res.status(200).json({ people: response.data });
      } catch (error) {
        res.status(500).json({ message: "Something went wrong." });
      }
    });
    
    mongoose.connect(
      "mongodb://localhost:27017/swfavorites",
      { useNewUrlParser: true },
      (err) => {
        if (err) {
          console.log(err);
        } else {
          app.listen(3000);
        }
      }
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    下面这个是 mongoose 的配置:

    const { Schema, model } = require("mongoose");
    
    const favoriteSchema = new Schema({
      type: String, // 'movie' | 'character'
      name: String,
      url: String,
    });
    
    const Favorite = model("Favorite", favoriteSchema);
    
    module.exports = Favorite;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Dockerfile:

    FROM node
    
    WORKDIR /app
    
    COPY package.json .
    
    RUN npm install
    
    COPY . .
    
    CMD ["node", "app.js"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    简单解释一下这个代码就是,它会创立几个 endpoints,有两个 endpoints 会直接与进行沟通 https://swapi.dev/api/films,获取数据。还会有两个 endpoints 与 mongodb 进行沟通,进行 POST 和 GET 的 request

    其中 https://swapi.dev/api/films 是一个 dummy API endpoint,是别人在网上 host 的:

    在这里插入图片描述

    而 mongodb 则是本机上进行安装,或者使用 docker 容器进行实现

    下面会提一下怎么配置本机,但是这里只会运行容器与容器之间的沟通

    docker build

    build 过程会报错:

    docker build -t favorite-app .
    [+] Building 7.3s (10/10)docker run --name favorites --rm -p 3000:3000 favorite-app
    (node:1) [MONGODB DRIVER] Warning: Current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
    (Use `node --trace-warnings ...` to show where the warning was created)
    MongoNetworkError: failed to connect to server [localhost:27017] on first connect [Error: connect ECONNREFUSED 127.0.0.1:27017
        at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1605:16) {
      name: 'MongoNetworkError'
    }]
        at Pool.<anonymous> (/app/node_modules/mongodb/lib/core/topologies/server.js:441:11)
        at Pool.emit (node:events:519:28)
        at /app/node_modules/mongodb/lib/core/connection/pool.js:564:14
        at /app/node_modules/mongodb/lib/core/connection/pool.js:1000:11
        at /app/node_modules/mongodb/lib/core/connection/connect.js:32:7
        at callback (/app/node_modules/mongodb/lib/core/connection/connect.js:300:5)
        at Socket.<anonymous> (/app/node_modules/mongodb/lib/core/connection/connect.js:330:7)
        at Object.onceWrapper (node:events:634:26)
        at Socket.emit (node:events:519:28)
        at emitErrorNT (node:internal/streams/destroy:169:8)
        at emitErrorCloseNT (node:internal/streams/destroy:128:3)
        at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    出错的方式可能有两个:

    1. 本机没有安装 mongodb

    2. 安装了但是没有配置好

    这里将 mongodb 连接的部分注释掉,重新运行一下:

    在这里插入图片描述

    发现 docker 容器和 https://swapi.dev/api/films 的交流沟通是没有任何问题的

    运行 mongodb 镜像

    这里运行一下结果就好了:

    docker run -d --name mongodb mongo
    # skip downloading process
    Status: Downloaded newer image for mongo:latest
    fb63b699a8ed81852c67057c3485ee4698be1437c3e6bef2bc3c87a1eca9a810
    
    • 1
    • 2
    • 3
    • 4

    本机与容器交流

    这里只要修改代码就好了:

    mongoose.connect(
      "mongodb://host.docker.internal:27017/swfavorites",
      { useNewUrlParser: true },
      (err) => {
        if (err) {
          console.log(err);
        } else {
          app.listen(3000);
        }
      }
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    localhost 改成 host.docker.internal 即可

    容器之间的沟通

    这个有两种方法

    直接沟通

    第一个直接获取容器的 IP 地址:

    # checked the exposed IP address by mongodocker container inspect mongodb | grep "IPAddress"
                "SecondaryIPAddresses": null,
                "IPAddress": "172.17.0.2",
                        "IPAddress": "172.17.0.2",
    
    • 1
    • 2
    • 3
    • 4
    • 5

    然后更新代码:

    mongoose.connect(
      "mongodb://172.17.0.2:27017/swfavorites",
      { useNewUrlParser: true },
      (err) => {
        if (err) {
          console.log(err);
        } else {
          app.listen(3000);
        }
      }
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    这个缺点在于每次重新运行容器的时候,IP 地址可能会出现改变,因此就需要修改代码,再重新 build

    使用 docker networks

    使用 network 可以让 docker 去管理 IP 地址,而非需要手动管理,这里第一步需要先通过 --network 去创建一个 network

    和 volume 不一样,docker 没有办法在容器运行的时候自动创建 network,所以先创建一个 network 是非常重要的事情

    在 network 创建了之后,docker 会自动找寻连接在当前 network 上的容器并完成沟通

    重新配置 mongo

    如果在没有创建 network 的情况下直接运行 --network 就会报错:

    docker run -d --rm --name mongodb --network favorites-net mongo
    60cdc3029a12b8e6af46728ce648598fa987977df2e8bf9f729596436266c24b
    docker: Error response from daemon: network favorites-net not found.
    
    • 1
    • 2
    • 3

    所以还是需要手动先创立一个 network:

    docker network create favorites-net
    f9385f787df37b608c6bc8bfb4619ff979c44312ee1f886965e17551dbde5d26
    ❯ docker network ls
    NETWORK ID     NAME            DRIVER    SCOPE
    624223e7a219   bridge          bridge    local
    f9385f787df3   favorites-net   bridge    local
    e0b7d35ecfa6   host            host      local
    6592d848be44   none            null      localdocker run -d --rm --name mongodb --network favorites-net mongo
    ac07e3660d2f04c515b7f635c37ae3e3e728f1c09c8afa9dfa0d64eb8e4cfe93
    ❯ docker ps
    CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS       NAMES
    ac07e3660d2f   mongo     "docker-entrypoint.s…"   11 seconds ago   Up 10 seconds   27017/tcp   mongodb
    ❯ docker container inspect mongodb | grep "net"
                "NetworkMode": "favorites-net",
                "SandboxKey": "/var/run/docker/netns/29cafc1c1f7a",
                    "favorites-net": {
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    更新 server 代码连接 network

    这里的变化是把 ip 地址改成容器名称:

    mongoose.connect(
      "mongodb://mongodb:27017/swfavorites",
      { useNewUrlParser: true },
      (err) => {
        if (err) {
          console.log(err);
        } else {
          app.listen(3000);
        }
      }
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    随后重新 build 和运行:

    docker run --name favorites --rm --network favorites-net -p 3000:3000 favorite-app
    (node:1) [MONGODB DRIVER] Warning: Current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
    (Use `node --trace-warnings ...` to show where the warning was created)
    
    • 1
    • 2
    • 3

    最终可以完成 CRUD 的操作:

    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    c++ SFML 获取ftp某个目录下所有的文件或者文件夹
    【算法题】LeetCode691、贴纸拼词(剪枝+记忆化搜索)
    使用jmeter压测nginx支持的最大长连接数
    普冉PY32F071单片机简单介绍,QFN64 48封装,支持 8 * 36 / 4 * 40 LCD
    淘宝分布式文件存储系统(一) -TFS
    Object.defineProperty和proxy代理模式
    数据结构入门————栈和队列(C语言/零基础/小白/新手+模拟实现+例题讲解)
    为什么软件可以被破解,但是压缩包却破解不了?
    开发中遇到的问题
    JVM 一张图带你了解内存分配过程 搞懂逃逸分析|标量替换|指针碰撞|空闲列表|TLAB
  • 原文地址:https://blog.csdn.net/weixin_42938619/article/details/138064904