LoginSignup
1
3

More than 3 years have passed since last update.

[Windows] Dockerを使用してMosquittoでMQTTサーバを構築する際に別コンテナにloalhostで接続できるようにする

Posted at

TL;DR

  • Mosquittoを使ってMQTTサーバを立てた際にコンテナ間でlocalhostで接続できないかと調査
  • docker-composeでnetwork_modeを「host」にすることでホスト端末と同じIPアドレスにすることで可能とわかった
  • GO言語のpaho.mqtt.golangライブラリを使って接続テストを実施

環境

  • Windows10
  • Docker Desktop 2.2.0.3
  • docker-composeはDocker Desktopに同梱
  • visual studio code 1.42.1[拡張機能Remote - Containers使用]
  • Mosquitto 1.6.9

完成したリポジトリ

ファイル

docker-compose.tml
version: '3'

services:
    api:
        build:
            dockerfile: Dockerfile
            context: ./containers/api
        volumes:
            - ./containers/api/src:/go/api
        tty: true
        network_mode: "host"
    mqtt:
        build:
            dockerfile: Dockerfile
            context: ./containers/mqtt
        ports: 
            - "1883:1883"
        volumes:
            - mosquittodata:/mosquitto/data
            - mosquittolog:/mosquitto/log
        tty: true
        network_mode: "host"

volumes:
    mosquittodata:
        driver: "local"
    mosquittolog:
        driver: "local"
  • apiコンテナとmqttコンテナにnetwork_modeで「host」を設定することでホスト端末と同じIPアドレスを使用する
main.go
package main

import (
    "crypto/tls"
    "flag"
    "fmt"
    "os"
    "strconv"
    "time"

    MQTT "github.com/eclipse/paho.mqtt.golang"
)

// Que Strut.
type Que struct {
    Server    string
    Sendtopic string
    Resvtopic string
    Qos       int
    Retained  bool
    Clientid  string
    Username  string
    Password  string
    Client    MQTT.Client
    Callback  MQTT.MessageHandler
}

// Connect func .
func (q *Que) Connect() error {
    connOpts := MQTT.NewClientOptions().AddBroker(q.Server).SetClientID(q.Clientid).SetCleanSession(true)
    if q.Username != "" {
        connOpts.SetUsername(q.Username)
        if q.Password != "" {
            connOpts.SetPassword(q.Password)
        }
    }
    tlsConfig := &tls.Config{InsecureSkipVerify: true, ClientAuth: tls.NoClientCert}
    connOpts.SetTLSConfig(tlsConfig)

    client := MQTT.NewClient(connOpts)
    if token := client.Connect(); token.Wait() && token.Error() != nil {
        return token.Error()
    }
    q.Client = client

    if q.Callback != nil {
        if token := q.Client.Subscribe(q.Resvtopic, byte(q.Qos), q.Callback); token.Wait() && token.Error() != nil {
            return token.Error()
        }
        fmt.Printf("[MQTT] Subscribe to %s\n", q.Sendtopic)
    }

    fmt.Printf("[MQTT] Connected to %s\n", q.Server)

    return nil
}

// Publish func .
func (q *Que) Publish(message string) error {
    if q.Client != nil {
        token := q.Client.Publish(q.Sendtopic, byte(q.Qos), q.Retained, message)
        if token == nil {
            return token.Error()
        }
        fmt.Printf("[MQTT] Sent to %s\n", q.Sendtopic)
    }

    return nil
}

// SetSubscribe - .
func (q *Que) SetSubscribe(callback MQTT.MessageHandler) error {
    if callback != nil {
        if token := q.Client.Subscribe(q.Resvtopic, byte(q.Qos), callback); token.Wait() && token.Error() != nil {
            return token.Error()
        }
        fmt.Printf("[MQTT] Subscribe to %s\n", q.Sendtopic)
    }

    return nil
}

func onMessageReceived(client MQTT.Client, message MQTT.Message) {
    fmt.Printf("[MQTT] Received to %s [Received Message: %s]\n", message.Topic(), message.Payload())
}

func main() {
    hostname, _ := os.Hostname()

    server := flag.String("server", "tcp://localhost:1883", "The full URL of the MQTT server to connect to")
    sendtopic := flag.String("sendtopic", "MQTT/Client/Update/TEST", "Topic to publish the messages on")
    resvtopic := flag.String("resvtopic", "MQTT/+/Update/#", "Topic to publish the messages on")
    qos := flag.Int("qos", 0, "The QoS to send the messages at")
    retained := flag.Bool("retained", false, "Are the messages sent with the retained flag")
    clientid := flag.String("clientid", hostname+strconv.Itoa(time.Now().Second()), "A clientid for the connection")
    username := flag.String("username", "", "A username to authenticate to the MQTT server")
    password := flag.String("password", "", "Password to match username")
    flag.Parse()

    q := &Que{
        Server:    *server,
        Sendtopic: *sendtopic,
        Resvtopic: *resvtopic,
        Qos:       *qos,
        Retained:  *retained,
        Clientid:  *clientid,
        Username:  *username,
        Password:  *password,
        Callback:  onMessageReceived,
    }

    err := q.Connect()
    if err != nil {
        fmt.Println(err)
        os.Exit(2)
    }

    if err := q.SetSubscribe(onMessageReceived); err != nil {
        fmt.Println(err)
        os.Exit(2)
    }

    for {
        time.Sleep(5000 * time.Millisecond)
        if err := q.Publish("test massage"); err != nil {
            fmt.Println(err)
            os.Exit(2)
        }
    }
}
  • MQTTサーバの接続先に「tcp://localhost:1883」を指定しているが、お互いのコンテナがnetwork_modeで「host」を設定しているので接続できる

MQTT接続実行結果

実行結果
root@docker-desktop:/go/api# go run main.go 
go: downloading github.com/eclipse/paho.mqtt.golang v1.2.0
go: downloading golang.org/x/net v0.0.0-20200320220750-118fecf932d8
[MQTT] Subscribe to MQTT/Client/Update/TEST
[MQTT] Connected to tcp://localhost:1883   
[MQTT] Subscribe to MQTT/Client/Update/TEST
[MQTT] Sent to MQTT/Client/Update/TEST
[MQTT] Received to MQTT/Client/Update/TEST [Received Message: test massage]
[MQTT] Sent to MQTT/Client/Update/TEST
[MQTT] Received to MQTT/Client/Update/TEST [Received Message: test massage]
[MQTT] Sent to MQTT/Client/Update/TEST
[MQTT] Received to MQTT/Client/Update/TEST [Received Message: test massage]

まとめ

MQTTサーバをDockerで構築する際にサーバをlocalhostにできないかな、というので調査していてnetwork_mode使えばできることがわかったので記事にしてみました。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3