On host machine I have docker-compose stack that have a service called
transactions-db
its a PostgreSQL container
I want to create a backup service using Golang to be able to create .sql to be used for restores later on
docker-compose.yml for backup service
version: "3.8"
services:
backup-service:
build:
context: .
dockerfile: Dockerfile
image: backup-service
container_name: backup-service
volumes:
- .:/app
- /var/run/docker.sock:/var/run/docker.sock
main.go
package main
import (
"context"
"fmt"
"os"
)
func main () {
result, err := ExecuteCommandOnContainer(context.Background(), ConnectToDocker(), "transactions-db")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(result.ExitCode)
}
docker.go
package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
func ConnectToDocker() *client.Client {
cli, err := client.NewClientWithOpts()
if err != nil {
fmt .Println(err)
}
return cli
}
func ExecuteCommandOnContainer(ctx context.Context, cli *client.Client, containerID string) (types.ContainerExecInspect, error) {
command := []string{"pg_dumpall", "-c", "-U", "user", "|", "gzip", ">", "backup/tr.sql"}
execConfig := types.ExecConfig{
Tty: true,
AttachStdin: true,
AttachStderr: true,
AttachStdout: true,
Cmd: command,
}
create, err := cli.ContainerExecCreate(ctx, containerID, execConfig)
if err != nil {
fmt .Println(err)
}
inspect, err := cli.ContainerExecInspect(ctx, create.ID)
if err != nil {
fmt .Println(err)
}
return inspect, nil
}
basically nothing happens when I run this code. I only get the following:
backup-service | 0
backup-service exited with code 0
I tried to normally run: go run .
I've also tried using my docker-compose up
same result
note: I've tested listing container it works but when trying to execute a command nothing
Related
I'm using a docker client with golang; in the following script, I'm trying to pass an environmental variable when a container is going to start.
package main
import (
"context"
"fmt"
"os/user"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)
func main() {
dockerClient, _ := client.NewClientWithOpts(client.FromEnv)
env := []string{}
for key, value := range map[string]string{"hi": "hoo"} {
env = append(env, fmt.Sprintf("%s=%s", key, value))
}
user, err := user.Current()
if err != nil {
fmt.Println(err)
}
config := container.Config{
User: fmt.Sprintf("%s:%s", user.Uid, user.Gid),
Image: "675d8442a90f",
Env: env,
}
response, err := dockerClient.ContainerCreate(context.Background(), &config, nil, nil, nil, "")
if err != nil {
fmt.Println(err)
}
if err = dockerClient.ContainerStart(context.Background(), response.ID, types.ContainerStartOptions{}); err != nil {
fmt.Println(err)
}
}
and my docker file is a simple one which I try to echo the hi env:
# Filename: Dockerfile
FROM ubuntu:latest
COPY . .
CMD ["echo", "$hi"]
When I built the image and passed the id to the script, it didn't echo the variable. Do you have any idea how I can use the environmental variables in the dockerfile, which are sent to the container by docker golang client?
Docker is running, ContainerExecCreate creates a container, but ContainerExecAttach returns: Cannot connect to the Docker daemon at unix: ///var/run/docker.sock in response. Is the docker daemon running?
What could be the problem.
import (
"archive/tar"
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"os"
"strconv"
"strings"
"time"
client "docker.io/go-docker"
"docker.io/go-docker/api/types"
"docker.io/go-docker/api/types/container"
"docker.io/go-docker/api/types/network"
"docker.io/go-docker/api/types/swarm"
"docker.io/go-docker/api/types/volume"
"github.com/containerd/containerd/reference"
"github.com/play-with-docker/play-with-docker/config"
)
func (d *docker) ExecAttach(instanceName string, command []string, out io.Writer) (int, error) {
e, err := d.c.ContainerExecCreate(context.Background(), instanceName, types.ExecConfig{Cmd: command, AttachStdout: true, AttachStderr: true, Tty: true})
if err != nil {
return 0, err
}
resp, err := d.c.ContainerExecAttach(context.Background(), e.ID, types.ExecConfig{AttachStdout: true, AttachStderr: true, Tty: true})
if err != nil {
return 0, err
}
}
It looks normal. May depend on the state of the docker at the time of the call. It is possible to check docker via Ping or just wait one second.
I am trying to create a containerSource for knative service. When I use docker run for the image it gives the output ("or the error from the code"). However when I apply the yaml file then kubectl log shows 'standard_init_linux.go:211: exec user process caused "no such file or directory"'. docker run shows that it is able to find the exec file. So I am not able to understand whats wrong. Someone please guide me through.
my yaml file:
apiVersion: sources.eventing.knative.dev/v1alpha1
kind: ContainerSource
metadata:
labels:
controller-tools.k8s.io: "1.0"
name: cloudevents-source
spec:
image: docker.io/username/pkt-event:latest
args:
- '--debug=true'
sink:
apiVersion: serving.knative.dev/v1alpha1
kind: Service
name: event-display
my go code for the dockerimage is:
package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"time"
"github.com/satori/go.uuid"
"knative.dev/eventing-contrib/pkg/kncloudevents"
"encoding/json"
// "io/ioutil"
// "knative.dev/eventing-contrib/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents"
"github.com/cloudevents/sdk-go/pkg/cloudevents"
"github.com/cloudevents/sdk-go/pkg/cloudevents/types"
"github.com/kelseyhightower/envconfig"
)
var (
eventSource string
eventType string
sink string
)
//var u, _ = uuid.NewV4()
var debug = flag.Bool("debug", false, "Enable debug mode (print more information)")
var source = flag.String("source", uuid.NewV4().String(), "Set custom Source for the driver")
func init() {
flag.StringVar(&eventSource, "eventSource", "", "the event-source (CloudEvents)")
flag.StringVar(&eventType, "eventType", "dev.knative.eventing.samples.pkt", "the event-type (CloudEvents)")
flag.StringVar(&sink, "sink", "", "the host url to send pkts to")
}
type envConfig struct {
// Sink URL where to send heartbeat cloudevents
Sink string `envconfig:"SINK"`
}
func main() {
flag.Parse()
var env envConfig
if err := envconfig.Process("", &env); err != nil {
log.Printf("[ERROR] Failed to process env var: %s", err)
os.Exit(1)
}
if env.Sink != "" {
sink = env.Sink
}
if eventSource == "" {
eventSource = fmt.Sprintf("https://knative.dev/eventing-contrib/cmd/heartbeats/#local/demo")
log.Printf("Source: %s", eventSource)
}
client, err := kncloudevents.NewDefaultClient(sink)
if err != nil {
log.Fatalf("failed to create client: %s", err.Error())
}
var period time.Duration
period = time.Duration(1) * time.Second
ticker := time.NewTicker(period)
for {
content := "Send data"
data, err := json.Marshal(content)
if err != nil {
fmt.Println(err)
}
event := cloudevents.Event{
Context: cloudevents.EventContextV02{
Type: "packet.invoke",
Source: *types.ParseURLRef(eventSource),
/*Extensions: map[string]interface{}{
"the": 42,
"heart": "yes",
"beats": true,
},*/
}.AsV02(),
Data: data,
}
if *debug{
log.Printf("Sending event %v", event)
} else {
if _, err := client.Send(context.TODO(), event); err != nil {
log.Printf("failed to send cloudevent: %s", err.Error())
}
}
<-ticker.C
}
}
And Dockerfile is:
FROM golang:1.12 as builder
RUN go version
WORKDIR ${GOPATH}/src/Event-driver
COPY ./ ./
RUN curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
##RUN dep ensure
RUN dep init
RUN dep ensure
RUN CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -v -o my-event my-event.go
RUN pwd && ls
FROM scratch
#FROM ubuntu:disco
COPY --from=builder /go/src/Event-driver/my-event /
ENTRYPOINT ["/my-event"]
That problem occurs because you're trying to run your binary from bash, but scratch has no bash.
I'm normally using alpina instead. To build for alpina you need the same environment variables, so probably you only need to change a second stage image.
I am looking forward to do something below like this using docker golang api
cmd : docker run -t -i -p 8989:8080 "image-name" /bin/bash
Also I am using golang sdk https://github.com/moby/moby/client or https://godoc.org/github.com/moby/moby/client and my docker api version is 1.30 (Client & Server both)
Here is the piece of code I am using
package main
import (
"fmt"
"github.com/docker/docker/client"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"golang.org/x/net/context"
"github.com/docker/go-connections/nat"
//"github.com/docker/docker/vendor/github.com/docker/go-connections/nat"
)
func check(err error) {
if err != nil {
panic(err)
}
}
func main(){
ctx := context.Background()
cli, err := client.NewEnvClient()
check(err)
config := &container.Config{
Image : image-name,
ExposedPorts: nat.PortSet{
"8080/tcp": struct{}{},
},
Cmd : [] string {"sh","-c","while true; do sleep always; done","/bin/bash"},
}
host_config := &container.HostConfig{
PortBindings: nat.PortMap{
"8080/tcp": []nat.PortBinding{
{
HostIP: "0.0.0.0",
HostPort: "8989",
},
},
},
}
resp, err := cli.ContainerCreate(ctx,config,host_config, nil,"")
check(err)
if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{});
err != nil {
panic(err)
}
}
After Compiling this code I get the following error
# command-line-arguments
src\main\createcontainer1.go:53: cannot use "github.com/docker/go-connections/nat".PortSet literal (type "github.com/docker/go-connections/nat".PortSet) as type "github.com/docker/docker/vendor/github.com/docker/go-connections/nat".PortSet in field value
src\main\createcontainer1.go:65: cannot use "github.com/docker/go-connections/nat".PortMap literal (type "github.com/docker/go-connections/nat".PortMap) as type "github.com/docker/docker/vendor/github.com/docker/go-connections/nat".PortMap in field value
If somebody knows what could be the problem and how to fix it.
Please answer to it as I am beginner with docker.
This is a Golang issue with how vendor/ works.
Remove the nested vendor directory:
rm -rf vendor/github.com/docker/docker/vendor
If you are using glide, you should use glide install -v when installing the dependency.
For more details, check this reported issue
My solution for OSX:
mv /Users/<user>/go/src/github.com/docker/docker/vendor/github.com/docker/go-connections/{nat,nat.old}
I'm using "golang.org/x/net/ipv4" in order to use its SetTTL function. Unfortunately it does not seem to work on Linux, only on Mac, even though the documentation indicates Linux supports all the functions.
Here's a minimal example of the problem, with a Dockerfile:
main.go:
package main
import (
"fmt"
"net"
"bufio"
xnet "golang.org/x/net/ipv4"
)
const Host = "google.com"
func main() {
var err error
conn, err := net.Dial("tcp4", Host + ":80")
if err != nil {
panic(err)
}
defer conn.Close()
xconn := xnet.NewConn(conn)
err = xconn.SetTTL(5)
if err != nil {
panic(err)
}
defer xconn.Close()
fmt.Fprint(conn, "GET / HTTP/1.1\r\nHOST: google.com\r\n\r\n")
firstLine, err := bufio.NewReader(xconn).ReadString('\n')
if err != nil {
panic(err)
}
fmt.Println(firstLine)
}
Dockerfile:
FROM golang:1.8.1-alpine
RUN apk --no-cache add git
RUN go get golang.org/x/net/ipv4
COPY . /go/src/me.com/me/xnetproblem
RUN go install me.com/me/xnetproblem
CMD ["/go/bin/xnetproblem"]
I run this command:
docker build -t xnet .
I get this output:
john xnetproblem > docker build -t xnet .
Sending build context to Docker daemon 90.62 kB
Step 1/6 : FROM golang:1.8.1-alpine
[snip]
Step 5/6 : RUN go install me.com/me/xnetproblem
---> Running in c3802fe61d63
# me.com/me/xnetproblem
src/me.com/me/xnetproblem/main.go:25: xconn.Close undefined (type *ipv4.Conn has no field or method Close)
src/me.com/me/xnetproblem/main.go:28: cannot use xconn (type *ipv4.Conn) as type io.Reader in argument to bufio.NewReader:
*ipv4.Conn does not implement io.Reader (missing Read method)
The command '/bin/sh -c go install me.com/me/xnetproblem' returned a non-zero code: 2
Using go install natively, instead of Docker, the program works on Mac but not on Linux.
Thanks to #JimB's comment I realized my Mac had an old version of the ipv4 package installed. After updating I was able to fix the code.
Here's a complete working version:
package main
import (
"fmt"
"net"
"bufio"
"golang.org/x/net/ipv4"
)
const Host = "google.com"
func main() {
var err error
conn, err := net.Dial("tcp4", Host + ":80")
if err != nil {
panic(err)
}
defer conn.Close()
if err = ipv4.NewConn(conn).SetTTL(5); err != nil {
panic(err)
}
fmt.Fprint(conn, fmt.Sprintf("GET / HTTP/1.1\r\nHost: %v\r\n\r\n", Host))
firstLine, err := bufio.NewReader(conn).ReadString('\n')
if err != nil {
panic(err)
}
fmt.Println(firstLine)
}
Here is the output:
HTTP/1.1 301 Moved Permanently