How to bind to IP using golang client?

I want to achieve the below using go client library for Docker Engine API.

docker run -d --name mysqltest -e MYSQL_ROOT_PASSWORD=test -p 192.168.0.211:13306:3306 mysql

I have done something like below:

portBindings := nat.PortMap{}
portBindings[nat.Port("3306")] = []nat.PortBinding{{HostIP: "192.168.0.211", HostPort: "13306"}}
hostConfig := &container.HostConfig{
		PortBindings: portBindings,
	}
	newcontainer, err := cli.ContainerCreate(context.Background(), &container.Config{
		Image: "mysql:latest",
	}, hostConfig, nil, nil, "mysqltestinstance")

It creates the container and binds container port to host IP 127.0.0.1 and host port 32768. If I run it again it binds to 32769, 32770 and so on.

I am not sure why it binds to 127.0.0.1 when I have specified 192.168.0.211. Also not sure why it chooses port 32768 and increments it by 1 for every run.

Can someone help me what I am doing wrong?

There is a docker --debug, but I am not sure if you can see API calls there.

If you are interested in the API calls the CLI is doing, then you could use a proxy. Create either a new file system or TCP socket and proxy all requests to original Docker socket, meanwhile print the JSON going back and forth.

Maybe docker-socket-proxy does the trick when setting log level to debug. (Link)

1 Like

I am doing the obvious here and ask ChatGPT: “please write go code for how to create a docker container and publish a port to a specific host ip”

That’s what ChatGPT returned:

Certainly! Below is an example Go code that uses the github.com/docker/docker package to create a Docker container and publish a port to a specific host IP:

package main

import (
	"context"
	"fmt"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
	"github.com/docker/docker/api/types/container"
)

func main() {
	// Replace these values with your desired container and port configurations
	imageName := "nginx:latest" // Docker image to use
	containerPort := "80"       // Port to be exposed inside the container
	hostPort := "8080"           // Port to be exposed on the host
	hostIP := "0.0.0.0"          // Host IP address to bind the port

	// Create a new Docker client
	cli, err := client.NewEnvClient()
	if err != nil {
		panic(err)
	}

	// Pull the Docker image
	fmt.Printf("Pulling image %s...\n", imageName)
	reader, err := cli.ImagePull(context.Background(), imageName, types.ImagePullOptions{})
	if err != nil {
		panic(err)
	}
	defer reader.Close()

	// Wait for the image to be pulled
	// Note: You may want to add a timeout or use a more sophisticated method in a production environment
	_, err = cli.ImageInspectWithRaw(context.Background(), imageName)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Image %s pulled successfully!\n", imageName)

	// Create container configuration
	config := &container.Config{
		Image: imageName,
		ExposedPorts: map[nat.Port]struct{}{
			nat.Port(containerPort + "/tcp"): {},
		},
	}

	// Set port binding
	hostBinding := nat.PortBinding{
		HostIP:   hostIP,
		HostPort: hostPort,
	}

	containerPortBinding := nat.PortMap{
		nat.Port(containerPort + "/tcp"): []nat.PortBinding{hostBinding},
	}

	// Create host configuration
	hostConfig := &container.HostConfig{
		PortBindings: containerPortBinding,
	}

	// Create the container
	fmt.Println("Creating container...")
	resp, err := cli.ContainerCreate(
		context.Background(),
		config,
		hostConfig,
		nil,
		nil,
		"")
	if err != nil {
		panic(err)
	}

	// Start the container
	fmt.Println("Starting container...")
	if err := cli.ContainerStart(context.Background(), resp.ID, types.ContainerStartOptions{}); err != nil {
		panic(err)
	}

	fmt.Printf("Container %s started successfully!\n", resp.ID)

	// Cleanup: Stop and remove the container after running
	defer func() {
		fmt.Printf("Stopping container %s...\n", resp.ID)
		if err := cli.ContainerStop(context.Background(), resp.ID, nil); err != nil {
			panic(err)
		}

		fmt.Printf("Removing container %s...\n", resp.ID)
		if err := cli.ContainerRemove(context.Background(), resp.ID, types.ContainerRemoveOptions{}); err != nil {
			panic(err)
		}
		fmt.Printf("Container %s removed successfully!\n", resp.ID)
	}()
}

Make sure to install the github.com/docker/docker package using the following command:

go get -u github.com/docker/docker

This code pulls the specified Docker image, creates a container based on that image, and binds the specified port to the specified host IP. Note that this example is for educational purposes, and in a production environment, you may want to add error handling, logging, and other improvements.

1 Like

Thank you, all I had to do was to add “/tcp” to the container port.