tcp-echo
Minimal .NET 8 TCP echo server. Every reply is prefixed with the instance identifier
(INSTANCE_ID env var, falling back to the hostname), and a [<id>] connected line is sent on connect.
Two instances are deployed behind Traefik:
| Instance | INSTANCE_ID | External port |
|---|---|---|
| a | echo-a | 9098 |
| b | echo-b | 9099 |
Build and push
Requires a prior docker login gitea.eitczech.com.
./build-push.ps1 -Tag 1.0.0 # pushes gitea.eitczech.com/public/tcp-echo-server:1.0.0
./build-push.ps1 -Tag 1.0.0 -AlsoLatest # additionally pushes :latest
The manifests reference gitea.eitczech.com/public/tcp-echo-server:latest. To pin a specific tag either edit
k8s/instance-a.yaml / k8s/instance-b.yaml, or after kubectl apply -k run:
kubectl -n tcp-echo set image deploy/tcp-echo-a deploy/tcp-echo-b tcp-echo=gitea.eitczech.com/public/tcp-echo-server:1.0.0
If the Gitea registry is private, create a pull secret in the namespace and reference it via imagePullSecrets.
Package description on Gitea
The Dockerfile sets the standard OCI labels (org.opencontainers.image.*). Gitea reads them from the pushed
image and shows them on the package page:
| Label | Shown as / effect |
|---|---|
description |
Package description text |
source |
Links the package to the repository with the same URL (repo must exist first) |
url, documentation, licenses, authors, vendor |
Metadata section on the package page |
version, revision, created |
Filled in by build-push.ps1 from the tag, git commit and current time |
To change the description, edit the LABEL in Dockerfile and rebuild. If the package was pushed before the
repository existed, link it manually: package page -> Settings -> Link to repository.
Deploy
kubectl apply -k k8s/
kubectl -n tcp-echo rollout status deploy/tcp-echo-a deploy/tcp-echo-b
30-traefik-entrypoint.yaml adds tcpechoa (9098) and tcpechob (9099) entrypoints to the k3s-managed
Traefik (Traefik restarts once). For a Helm-managed Traefik, drop that file from kustomization.yaml and run:
helm upgrade traefik traefik/traefik -n kube-system --reuse-values -f k8s/traefik-values.yaml
If Traefik's Service is a LoadBalancer, make sure the cloud/VPS firewall allows TCP 9098 and 9099.
Test
Linux / macOS
$ nc <server-ip> 9098
[echo-a] connected
hello
[echo-a] hello
$ nc <server-ip> 9099
[echo-b] connected
hello
[echo-b] hello
Windows (PowerShell)
Windows has no nc. Use the included script, which opens a TCP connection, prints the greeting,
sends a message and prints the echoed reply:
. est-echo.ps1 -Server <server-ip> -Port 9098
. est-echo.ps1 -Server <server-ip> -Port 9099 -Message "ping"
Expected output:
Connecting to <server-ip>:9098 ...
<- [echo-a] connected
-> hello
<- [echo-a] hello
Just to check the port is reachable (no echo):
Test-NetConnection -ComputerName <server-ip> -Port 9098
For an interactive session, telnet <server-ip> 9098 works if the Telnet Client feature is enabled
(Enable-WindowsOptionalFeature -Online -FeatureName TelnetClient), or install ncat via winget install Insecure.Nmap.
Local test with Docker
docker build -t tcp-echo:local .
docker run --rm -d --name tcp-echo-test -e INSTANCE_ID=echo-local -p 9099:9099 tcp-echo:local
. est-echo.ps1 -Server localhost -Port 9099
docker rm -f tcp-echo-test