From cae122354f49782b03ec944a2504f8bdfe218017 Mon Sep 17 00:00:00 2001 From: Julien Leicher Date: Tue, 23 Apr 2024 19:53:32 +0200 Subject: [PATCH] chore: add example project to expose multiple kind of ports --- .dockerignore | 2 +- examples/go-api/.dockerignore | 2 + .../{docker-compose.yml => compose.yml} | 0 .../{docker-compose.yml => compose.yml} | 0 examples/multiple-ports/.dockerignore | 2 + examples/multiple-ports/Dockerfile | 14 ++ examples/multiple-ports/README.md | 20 ++ examples/multiple-ports/compose.yml | 11 + examples/multiple-ports/go.mod | 3 + examples/multiple-ports/main.go | 206 ++++++++++++++++++ examples/sveltekit-hello/.dockerignore | 1 + 11 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 examples/go-api/.dockerignore rename examples/go-api/{docker-compose.yml => compose.yml} (100%) rename examples/minimal/{docker-compose.yml => compose.yml} (100%) create mode 100644 examples/multiple-ports/.dockerignore create mode 100644 examples/multiple-ports/Dockerfile create mode 100644 examples/multiple-ports/README.md create mode 100644 examples/multiple-ports/compose.yml create mode 100644 examples/multiple-ports/go.mod create mode 100644 examples/multiple-ports/main.go diff --git a/.dockerignore b/.dockerignore index 1865e5f5..99c4d3ca 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,6 @@ examples Dockerfile -docker-compose.yml +compose.yml docs node_modules **/Dockerfile diff --git a/examples/go-api/.dockerignore b/examples/go-api/.dockerignore new file mode 100644 index 00000000..f3662c93 --- /dev/null +++ b/examples/go-api/.dockerignore @@ -0,0 +1,2 @@ +Dockerfile +compose.yml \ No newline at end of file diff --git a/examples/go-api/docker-compose.yml b/examples/go-api/compose.yml similarity index 100% rename from examples/go-api/docker-compose.yml rename to examples/go-api/compose.yml diff --git a/examples/minimal/docker-compose.yml b/examples/minimal/compose.yml similarity index 100% rename from examples/minimal/docker-compose.yml rename to examples/minimal/compose.yml diff --git a/examples/multiple-ports/.dockerignore b/examples/multiple-ports/.dockerignore new file mode 100644 index 00000000..f3662c93 --- /dev/null +++ b/examples/multiple-ports/.dockerignore @@ -0,0 +1,2 @@ +Dockerfile +compose.yml \ No newline at end of file diff --git a/examples/multiple-ports/Dockerfile b/examples/multiple-ports/Dockerfile new file mode 100644 index 00000000..4daacff1 --- /dev/null +++ b/examples/multiple-ports/Dockerfile @@ -0,0 +1,14 @@ +FROM golang:1.21-alpine AS builder +WORKDIR /app +COPY go.* ./ +RUN go mod download +COPY . . +RUN go build -o app main.go + +FROM alpine:3.16 AS runner +RUN addgroup --system app +RUN adduser --system app +USER app +WORKDIR /app +COPY --from=builder --chown=app:app /app/app ./ +ENTRYPOINT ["./app"] \ No newline at end of file diff --git a/examples/multiple-ports/README.md b/examples/multiple-ports/README.md new file mode 100644 index 00000000..c43d64c1 --- /dev/null +++ b/examples/multiple-ports/README.md @@ -0,0 +1,20 @@ +# multiple-ports + +Quick & dirty project to test the **seelf** ability to handle multiple ports of specific types and check how they are managed by traefik. + +## Usage + +```sh +go run main.go -web 8080,8081 -tcp 9854,9855 -udp 9856,9857 +``` + +## How to test + +Quick & dirty ways to test if the server is actually listening. + +```sh +curl http://localhost:8080 # HTTP +curl telnet://localhost:9855 <<< text # TCP +nc -v localhost 9855 # Other way for TCP +nc -v -u localhost 9856 # UDP +``` diff --git a/examples/multiple-ports/compose.yml b/examples/multiple-ports/compose.yml new file mode 100644 index 00000000..aabd8d65 --- /dev/null +++ b/examples/multiple-ports/compose.yml @@ -0,0 +1,11 @@ +services: + app: + build: . + command: -web 8080,8081 -tcp 8082,8083 -udp 8084,8085 + ports: + - "8080:8080" + - "8081:8081" + - "8082:8082/tcp" + - "8083:8083/tcp" + - "8084:8084/udp" + - "8085:8085/udp" \ No newline at end of file diff --git a/examples/multiple-ports/go.mod b/examples/multiple-ports/go.mod new file mode 100644 index 00000000..0867a59f --- /dev/null +++ b/examples/multiple-ports/go.mod @@ -0,0 +1,3 @@ +module github.com/YuukanOO/seelf/examples/multiple-ports + +go 1.21.5 diff --git a/examples/multiple-ports/main.go b/examples/multiple-ports/main.go new file mode 100644 index 00000000..8bb00ca7 --- /dev/null +++ b/examples/multiple-ports/main.go @@ -0,0 +1,206 @@ +package main + +import ( + "context" + "errors" + "flag" + "log" + "net" + "net/http" + "os" + "os/signal" + "strconv" + "strings" + "sync" + "syscall" +) + +func main() { + var ( + web, tcp, udp string + wg sync.WaitGroup + ) + + flag.StringVar(&web, "web", "", "Comma separated list of ports on which to expose a tiny echo web server") + flag.StringVar(&tcp, "tcp", "", "Comma separated list of ports on which to expose a tiny echo TCP server") + flag.StringVar(&udp, "udp", "", "Comma separated list of ports on which to expose a tiny echo UDP server") + + flag.Parse() + + exposeHttp(&wg, parsePorts(web)...) + exposeTCP(&wg, parsePorts(tcp)...) + exposeUDP(&wg, parsePorts(udp)...) + + wg.Wait() +} + +func exposeHttp(wg *sync.WaitGroup, ports ...int) { + for _, port := range ports { + server := http.Server{ + Addr: ":" + strconv.Itoa(port), + } + + server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("Hello from " + server.Addr)) + }) + + wg.Add(1) + + go func() { + defer wg.Done() + + exit := makeExitChannel() + + go func() { + log.Printf("Starting HTTP server on %s", server.Addr) + if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + log.Printf("Failed to start HTTP server on %s: %v", server.Addr, err) + exit <- syscall.SIGTERM + } + }() + + <-exit + log.Printf("Shutting down HTTP server on %s", server.Addr) + server.Shutdown(context.Background()) + }() + } +} + +func exposeTCP(wg *sync.WaitGroup, ports ...int) { + for _, port := range ports { + addr := net.TCPAddr{Port: port} + wg.Add(1) + + go func() { + defer wg.Done() + + var ( + exit = makeExitChannel() + listener *net.TCPListener + err error + ) + + go func() { + log.Printf("Starting TCP server on %s", addr.String()) + + listener, err = net.ListenTCP("tcp", &addr) + + if err != nil { + log.Printf("Failed to start TCP server on %s: %v", addr.String(), err) + exit <- syscall.SIGTERM + return + } + + for { + conn, err := listener.Accept() + + if errors.Is(err, net.ErrClosed) { + return + } + + if err != nil { + log.Printf("Failed to accept connection on %s: %v", addr.String(), err) + continue + } + + conn.Write([]byte("Hello from " + conn.LocalAddr().String())) + conn.Close() + } + }() + + <-exit + + if listener == nil { + return + } + + log.Printf("Shutting down TCP server on %s", addr.String()) + listener.Close() + }() + } +} + +func exposeUDP(wg *sync.WaitGroup, ports ...int) { + for _, port := range ports { + addr := net.UDPAddr{Port: port} + wg.Add(1) + + go func() { + defer wg.Done() + + var ( + exit = makeExitChannel() + conn *net.UDPConn + err error + ) + + go func() { + log.Printf("Starting UDP server on %s", addr.String()) + + conn, err = net.ListenUDP("udp", &addr) + + if err != nil { + log.Printf("Failed to start UDP server on %s: %v", addr.String(), err) + exit <- syscall.SIGTERM + return + } + + buf := make([]byte, 1024) + + for { + _, addr, err := conn.ReadFrom(buf) + + if errors.Is(err, net.ErrClosed) { + return + } + + if err != nil { + log.Printf("Failed to read from UDP connection on %s: %v", addr.String(), err) + continue + } + + conn.WriteTo([]byte("Hello from "+conn.LocalAddr().String()), addr) + } + }() + + <-exit + + if conn == nil { + return + } + + log.Printf("Shutting down UDP server on %s", addr.String()) + conn.Close() + }() + } +} + +func makeExitChannel() chan os.Signal { + exit := make(chan os.Signal, 1) + signal.Notify(exit, syscall.SIGINT, syscall.SIGTERM) + return exit +} + +func parsePorts(value string) []int { + strs := strings.Split(value, ",") + ports := make([]int, 0, len(strs)) + + for _, str := range strs { + str = strings.TrimSpace(str) + + if str == "" { + continue + } + + p, err := strconv.Atoi(str) + + if err != nil { + log.Printf("Failed to parse port %s: %v", str, err) + continue + } + + ports = append(ports, p) + } + + return ports +} diff --git a/examples/sveltekit-hello/.dockerignore b/examples/sveltekit-hello/.dockerignore index 89df79a3..30312fff 100644 --- a/examples/sveltekit-hello/.dockerignore +++ b/examples/sveltekit-hello/.dockerignore @@ -1,2 +1,3 @@ Dockerfile +compose.yml node_modules \ No newline at end of file