最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Docker Volume Socket Release Issue - Stack Overflow

programmeradmin3浏览0评论

Having some application that is ran within a container. Besides the rest it starts listening a unix socket within a pre mounted volume directory. Previously file is pre cleaned up if exists any.

The problem is that if application doesn't properly close the socket on exit (as expected next app instance removes previous socket) eventually the socket couldn't be removed from within the container failing with operation not supported.

Anyway the same time the same problem socket could be freely removed from the host shell.

As example

main.go

package main

import (
    "fmt"
    "net"
    "os"
    "strconv"
    "time"
)

func main() {
    args := os.Args
    socket := args[1]

    err := os.Remove(socket)

    if err != nil && !os.IsNotExist(err) {
        panic(fmt.Errorf("socket remove error\n%w", err))
    }

    listener, err := net.Listen("unix", socket)
    if err != nil {
        panic(err)
    }

    fmt.Printf("listener %p\n", listener)

    if len(args) > 2 {
        sleepText := args[2]
        sleepSeconds, err := strconv.Atoi(sleepText)
        if err != nil {
            panic(fmt.Errorf("wrong sleep seconds number %s\n%w", sleepText, err))
        }
        fmt.Printf("waiting %d seconds\n", sleepSeconds)

        time.Sleep(time.Second * time.Duration(sleepSeconds))
    }

}

Dockerfile

FROM golang:1.23.4-alpine3.21 AS builder

WORKDIR /app
COPY . .

RUN go mod init socktest
RUN go build .

ENTRYPOINT ["/app/socktest"]

Building

docker build -t socktest/test.local .

Running repeatedly

VOLUME=$HOME/tmp/socktest
docker run --rm -it -v "$VOLUME:$VOLUME" socktest/test.local $VOLUME/socket

eventually will fail with operation not supported trying pre clean up previous socket.

What is interesting

  1. Adding after socket creation code to release the socket solves the problem
    listener, err := net.Listen("unix", socket)
    if err != nil {
        panic(err)
    }

    // Release socket on exit
    defer listener.Close()
  1. As mentioned socket could be still freely removed from host shell

  2. It is needed 3 application run cycles to fall into an issue.

    • socket is created
    • previous socket removed + recreated new one
    • fails to remove second socket
  3. If we will force application to wait a little and remove meanwhile the socket manually from within the container with the same volume. So the issue is not reproduced neither on the app flow nor at rm action it self regardless repeating the flow

docker run --rm -it -v "$VOLUME:$VOLUME" socktest/test.local $VOLUME/socket 15 # wait 15 seconds

# in other terminal
docker run --rm -it -v "$VOLUME:$VOLUME" --entrypoint rm socktest/test.local $VOLUME/socket
  1. It even works well if we remove the socket after the app is finished right within the container but at a separate process (not the same that would recreate the new socket instance)
for i in `seq 1 10` 
do 
    docker run --rm -it -v "$VOLUME:$VOLUME" socktest/test.local $VOLUME/socket
    docker run --rm -it -v "$VOLUME:$VOLUME" --entrypoint rm socktest/test.local $VOLUME/socket
done

It looks it matters that the socket is both was removed and recreated within the same containerized process to cause the issue.

So what in fact makes these socket files behave the different way (change any properties or attributes) after ungraceful socket release. And how actually gracefully remove it anyway afterwards within the container?

I believe macOS Docker Desktop is used matters here to be mentioned.

Thank you

发布评论

评论列表(0)

  1. 暂无评论