How to use docker cli in golang to create subnet - docker

I'm trying to create a docker network for my application written in Golang.
I'm aware that I can use this NetworkCreate function, but I'm not sure how to specify the network option.
In the regular terminal console, I can just create the network with
docker network create -d bridge --subnet=174.3.12.5/16 mynet
But how to use the NetworkCreate() as an equivalent for this network creation?

package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
)
func main() {
cli, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
fmt.Println(err)
}
newnetwork := types.NetworkCreate{IPAM: &network.IPAM{
Driver: "default",
Config: []network.IPAMConfig{network.IPAMConfig{
Subnet: "174.3.12.5/16",
}},
}}
res, err := cli.NetworkCreate(context.Background(), "test", newnetwork)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(res)
}
this is a minimal implementable example. the name for driver is default.

You can specify the network options via the NetworkCreate options struct.
If you want to convert the command docker network create -d bridge --subnet=174.3.12.5/16 mynet to a golang equivalent, It'll look something like this:
networkResponse, err := client.NetworkCreate(context.Background(), "mynet", types.NetworkCreate{
Driver: "bridge",
IPAM: &network.IPAM{
Config: network.IPAMConfig{
Subnet: "174.3.12.5/16",
},
},
})

You can use exec.Command(...).CombinedOutput()

Related

Golang POST request from one to another docker container

I have a server in one docker container (port 5044) and client in other docker container (port 4545). I want to send POST request from client to server but i get an error message "Post "http://127.0.0.1:5044/check": dial tcp 127.0.0.1:5044: connect: connection refused".
json, err := json.Marshal(x)
if err != nil {
log.Fatal(err)
}
resp, err := http.Post("http://127.0.0.1:5044/check", "application/json", bytes.NewBuffer(json))
//Handle Error
if err != nil {
log.Fatalf("An Error Occured %v", err)
}
defer resp.Body.Close()
//Read the response body
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
return string(body)
I can send post request using postman and everything is ok.
I tried to connect to test internet service (https://ptsv2.com/) and it works as well. It seems like golang doesnt want to conenct to the local server form docker :/
your docker app is accessible from it's "external port" with Postman
But to allow them to communicate together they need to be on the same network
the easiest way to do it is to use a docker-compose (instead of manually creating the neworks) official link
version: '3'
services:
first:
build:
context: ./your-first-app
dockerfile: Dockerfile
ports:
- '1800:1800'
networks:
my-network:
second:
build:
context: ./your-second-app
dockerfile: Dockerfile
ports:
- '1801:1801'
networks:
my-network:
networks:
my-network:
your network is declared at the end of the line, and it's linked to both your Docker service via the tag networks (below ports)
The best practice to connect to the docker container is by using the container name e.g. http://app_one:5044/check, you can find the container name by using the docker ps command. in order to connect with the container name, all containers have to be in the same network.
But if you want to use IP this is the way.
Each container has a different IP address, in order to connect from one container to another you need to know the container IP address that you want to connect. 127.0.0.1 is not the container IP, it's the host IP.
you can to find the IP address of the container by this command, docker inspect your_container_name you will see the IP in networking section
"Networks": {
"bridge_network": {
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.37",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
}
}
in my example 172.18.0.37 is my container IP address. so I need to use that by to communicate e.g. http://172.18.0.37:5044/check
be aware that IPAddress if the container can change when you restart the container so it's better to use container name
Find your service name from your docker-compose.yml file for the server and replace this:
resp, err := http.Post("http://127.0.0.1:5044/check", "application/json", bytes.NewBuffer(json))
with this:
resp, err := http.Post("http://<serviceName>:5044/check", "application/json", bytes.NewBuffer(json))

Unable to mount a folder in Docker from container with Go Docker Engine API

I am trying to run docker inside container using Go Docker Engine API. I am able to mount a folder from host system to the container but only empty dir is being copied into the docker inside the container. Please help me out if there is any alternative for the same. I am starting my container using following command.
docker run --rm -v C:\Users\user\source\repos\game:/app/myrepo -v /var/run/docker.sock:/var/run/docker.sock testimage
Attached is the piece of code.
Go Docker SDK code to start container
resp, err := cli.ContainerCreate(ctx, &container.Config{
Image: "hello-image",
Cmd: []string{"ls"}, #the actual cmd would look different
Tty: true,
}, &container.HostConfig{
Binds: []string{
"/app/myrepo:/myrepo",
},
}, nil, nil, containername)
if err != nil {
panic(err)
}
updated Code for binds with absolute path
resp, err := cli.ContainerCreate(ctx, &container.Config{
Image: "hello-image",
Cmd: []string{"ls"}, #the actual cmd would look different
Tty: true,
}, &container.HostConfig{
Mounts: []mount.Mount{
{
Type: mount.TypeBind,
Source: "/app/myrepo",
Target: "/myrepo",
},
},
}, nil, nil, containername)
if err != nil {
panic(err)
}
As discussed in the comments the OP is running an app in a container. The app is connecting to the docker daemon on the host (via shared /var/run/docker.sock) and attempting to create a container. The issue was that the request includes a mount point, the source being /app/myrepo, which a source path that is valid within the container but not on the host.
To aid in understanding why this is an issue you need to consider how the API request is made. Your code will generate a JSON formatted request; this will include something like this:
...
"HostConfig": {
...
"Mounts": [
{
"Source": "/app/myrepo",
"Destination": "/myrepo",
}
]
}
It's important to note that the Source path is passed as a string and the Docker Daemon will interpret this in the hosts (e.g. the windows box) context. When it attempts to locate the requested path (/app/myrepo) it will not find it because that path does not exist on the host. To correct this you need to send a valid path e.g.
Mounts: []mount.Mount{
{
Type: mount.TypeBind,
Source: "c:/Users/user/source/repos/game",
Target: "/myrepo",
},
}
One note of caution; accessing the Docker API in this way (bind mount /var/run/docker.sock:) is convenient but if someone gains access to the container then they also gain full control of all containers (because they can access the Docker API). You may want to consider using a proxy (for example).

How to run a container on user-defined network in Go client for the Docker Engine API?

I'm using client.ContainerCreate & client.ContainerStart to run a container locally.
resp, err := cli.ContainerCreate(ctx, &container.Config{
Image: repoName + "/" + imageName,
Cmd: []string{"--env", "stage=local", "--spec", testSpecFile},
Tty: false,
}, &container.HostConfig{
Binds: []string{
"ui-automation:/automation",
},
}, nil, nil, "")
And following are the available networks,
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
1b17539cfd94 bridge bridge local
09dcddcdebad host host local
2d5bb8da5fe6 kind bridge local
1d9dd2f2a18a none null local
Now by default it's running on default bridge network. In CLI, if I wanted to attach my container to some other network, say host, I could do,
docker run --network host <image>
How to achieve the same using the above mentioned golang library ?

How to write docker private registry reverse proxy via golang?

I'm trying to create a reverse proxy in golang for my private registry, however the following snippet has unexpected behavior:
package main
import (
"fmt"
"log"
"net/http"
"net/http/httputil"
"net/url"
)
func main() {
http.HandleFunc("/", ServeHTTP)
http.ListenAndServe("0.0.0.0:9090", nil)
}
func ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Printf(r.URL.Path + "\n")
remote, err := url.Parse("http://localhost:10000")
if err != nil {
log.Fatal(err)
}
proxy := httputil.NewSingleHostReverseProxy(remote)
proxy.ServeHTTP(w, r)
}
I used docker run -d -p 10000:5000 -v docker_image:/var/lib/registry\ registry to run a private docker registry container.
After running the code, I used curl 127.0.0.1:9090/v2/_catalog and I got the correct answer, but when I used docker push 127.0.0.1:9090/hello-world:latest (after running docker tag), the docker client threw Get "http://127.0.0.1:9090/v2/": dial tcp 127.0.0.1:9090: connect: connection refused.
I checked the logs and it seems that my code does not even get the http request.
What could I do to achieve the desired result?

how to create container with memory limit in docker go client

I am trying to create a container with memory limit using the docker go client - https://godoc.org/github.com/docker/docker/client#Client.ContainerCreate
However I cannot figure out where to add these parameters in the function.
docker run -m 250m --name test repo/tag
In the docker api, it comes under Host Config structure but in go doc I saw the option under resources which is used in HostConfig - https://godoc.org/github.com/docker/docker/api/types/container#HostConfig
Calling like this
import(
....
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
)
...
resp, err1 := cli.ContainerCreate(ctx,
&container.Config{
User: strconv.Itoa(os.Getuid()), // avoid permission issues
Image: cfg.ImageName,
AttachStdin: false,
AttachStdout: true,
AttachStderr: true,
Tty: true,
ExposedPorts: exposedPorts,
Labels: labels,
Env: envVars,
},
&container.HostConfig{
Binds: binds,
NetworkMode: container.NetworkMode(cfg.Network),
PortBindings: nat.PortMap{
"1880": []nat.PortBinding{
nat.PortBinding{
HostIP: "",
HostPort: "1880",
},
}},
AutoRemove: true,
Memory : 262144000, //this does not work
},
nil, // &network.NetworkingConfig{},
name,
)
unknown field 'Memory' in struct literal of type container.HostConfig. Since it does not have a field name and only type I have no idea how to add resources to Hostconfig. Any help is appreciated - I am a newbie at go and am trying to tweak an opensource project I was using - redzilla - due to my system's resource constraints
You can define memory limit using Resources field of HostConfig struct.
Resources: container.Resources{ Memory:3e+7 }

Resources