From 3c1c08f664a13d97a28e48d5a24d5d314ca3125c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sankar=20=E0=AE=9A=E0=AE=99=E0=AF=8D=E0=AE=95=E0=AE=B0?= =?UTF-8?q?=E0=AF=8D?= Date: Fri, 31 May 2024 16:08:51 +0530 Subject: [PATCH 1/4] go-postgres-react starting with go --- go-postgres-react/go/Dockerfile | 19 +++++++++ go-postgres-react/go/Kraftfile | 7 ++++ go-postgres-react/go/README.md | 20 +++++++++ go-postgres-react/go/go.mod | 5 +++ go-postgres-react/go/go.sum | 2 + go-postgres-react/go/server.go | 74 +++++++++++++++++++++++++++++++++ 6 files changed, 127 insertions(+) create mode 100644 go-postgres-react/go/Dockerfile create mode 100644 go-postgres-react/go/Kraftfile create mode 100644 go-postgres-react/go/README.md create mode 100644 go-postgres-react/go/go.mod create mode 100644 go-postgres-react/go/go.sum create mode 100644 go-postgres-react/go/server.go diff --git a/go-postgres-react/go/Dockerfile b/go-postgres-react/go/Dockerfile new file mode 100644 index 00000000..3aa4b6f1 --- /dev/null +++ b/go-postgres-react/go/Dockerfile @@ -0,0 +1,19 @@ +FROM --platform=linux/x86_64 golang:1.22.3-bookworm AS build + +WORKDIR /src + +COPY . /src/ + +RUN set -xe; \ + go build \ + -buildmode=pie \ + -ldflags "-linkmode external -extldflags -static-pie" \ + -tags netgo \ + -o /server server.go \ + ; + +FROM scratch + +COPY --from=build /server /server +COPY --from=build /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/ +COPY --from=build /lib64/ld-linux-x86-64.so.2 /lib64/ diff --git a/go-postgres-react/go/Kraftfile b/go-postgres-react/go/Kraftfile new file mode 100644 index 00000000..abe5d412 --- /dev/null +++ b/go-postgres-react/go/Kraftfile @@ -0,0 +1,7 @@ +spec: v0.6 + +runtime: base:latest + +rootfs: ./Dockerfile + +cmd: ["/server"] diff --git a/go-postgres-react/go/README.md b/go-postgres-react/go/README.md new file mode 100644 index 00000000..321519b9 --- /dev/null +++ b/go-postgres-react/go/README.md @@ -0,0 +1,20 @@ +# Simple Go 1.21 HTTP Server + +This is a simple HTTP server written in the [Go](https://go.dev/) programming language. + +To run this example on KraftCloud, first [install the `kraft` CLI tool](https://unikraft.org/docs/cli). +Then clone this examples repository and `cd` into this directory, and invoke: + +```console +kraft cloud deploy --metro fra0 -p 443:8080 . +``` + +The command will build and deploy the `server.go` source code file. + +After deploying, you can query the service using the provided URL. + +## Learn more + +- [Go's Documentation](https://go.dev/doc/) +- [KraftCloud's Documentation](https://docs.kraft.cloud) +- [Building `Dockerfile` Images with `Buildkit`](https://unikraft.org/guides/building-dockerfile-images-with-buildkit) diff --git a/go-postgres-react/go/go.mod b/go-postgres-react/go/go.mod new file mode 100644 index 00000000..09c0293f --- /dev/null +++ b/go-postgres-react/go/go.mod @@ -0,0 +1,5 @@ +module github.com/kraftcloud/examples/go-postgres-react/go + +go 1.22.3 + +require github.com/lib/pq v1.10.9 diff --git a/go-postgres-react/go/go.sum b/go-postgres-react/go/go.sum new file mode 100644 index 00000000..aeddeae3 --- /dev/null +++ b/go-postgres-react/go/go.sum @@ -0,0 +1,2 @@ +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= diff --git a/go-postgres-react/go/server.go b/go-postgres-react/go/server.go new file mode 100644 index 00000000..c76afc71 --- /dev/null +++ b/go-postgres-react/go/server.go @@ -0,0 +1,74 @@ +package main + +import ( + "database/sql" + "encoding/json" + "fmt" + "net/http" + + _ "github.com/lib/pq" +) + +type Contact struct { + Name string `json:"name"` + Email string `json:"email"` +} + +var db *sql.DB + +func main() { + var err error + db, err = sql.Open( + "postgres", + "user=yourusername dbname=yourdbname sslmode=disable", + ) + if err != nil { + panic(err) + } + + http.HandleFunc("/contacts", contactsHandler) + + fmt.Println("Listening on :8080...") + http.ListenAndServe(":8080", nil) +} + +func contactsHandler(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + rows, err := db.Query("SELECT name, email FROM contacts") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer rows.Close() + + var contacts []Contact + for rows.Next() { + var c Contact + if err := rows.Scan(&c.Name, &c.Email); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + contacts = append(contacts, c) + } + + json.NewEncoder(w).Encode(contacts) + case http.MethodPost: + var c Contact + json.NewDecoder(r.Body).Decode(&c) + + _, err := db.Exec( + "INSERT INTO contacts(name, email) VALUES($1, $2)", + c.Name, + c.Email, + ) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + json.NewEncoder(w).Encode(c) + default: + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + } +} From b69b1860a05ed4ff412fcddf1fb02b7d87bb1723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sankar=20=E0=AE=9A=E0=AE=99=E0=AF=8D=E0=AE=95=E0=AE=B0?= =?UTF-8?q?=E0=AF=8D?= Date: Fri, 31 May 2024 18:12:01 +0530 Subject: [PATCH 2/4] Update README for db+backend instructions --- go-postgres-react/README.md | 68 ++++++++++++++++++++++++++++++++++ go-postgres-react/go/server.go | 2 +- 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 go-postgres-react/README.md diff --git a/go-postgres-react/README.md b/go-postgres-react/README.md new file mode 100644 index 00000000..8eadeaae --- /dev/null +++ b/go-postgres-react/README.md @@ -0,0 +1,68 @@ +# go-postgres-react + +This is for creating a Contacts application with the following components: + +- a Golang backend +- a Postgresql database for saving data + -- the corresponding Volume for persistent storage +- a react frontend app for serving the UI + +## Create a volume and deploy postgresql + +``` +❯ kraft cloud deploy --metro fra0 -M 1024 -e POSTGRES_PASSWORD=unikraft -e PGDATA=/volume/postgres -v postgres:/volume -p 5432:5432/tls . + W could not parse image name: invalid reference format: repository name must be lowercase +[+] building rootfs... done! x86_64 [24.3s] +[+] packaging index.unikraft.io/sp/postgres:latest... done! kraftcloud/x86_64 [0.2s] +[+] pushing index.unikraft.io/sp/postgres:latest (kraftcloud/x86_64)... done! [50.3s] + +[●] Deployed successfully! + │ + ├────────── name: postgres-wahr0 + ├────────── uuid: 51095ece-2c34-4ec7-85c9-af0be864c91a + ├───────── state: running + ├──────── domain: cool-sound-5t2t69gg.fra0.kraft.host + ├───────── image: sp/postgres@sha256:944874221c4fb0bd5a617e5e32b05415db071d4bd964eaca822989f772fa3083 + ├───── boot time: 617.25 ms + ├──────── memory: 1024 MiB + ├─ service group: cool-sound-5t2t69gg + ├── private fqdn: postgres-wahr0.internal + ├──── private ip: 172.18.175.4 + └────────── args: wrapper.sh docker-entrypoint.sh postgres + +``` + +```console +$ cd github.com/kraftcloud/examples/postgres + +github.com/kraftcloud/examples/postgres$ kraft cloud volume create --name postgres --size 200 + +github.com/kraftcloud/examples/postgres$ kraft cloud deploy --metro fra0 -M 1024 -e POSTGRES_PASSWORD=unikraft -e PGDATA=/volume/postgres -v postgres:/volume -p 5432:5432/tls . +(Search for `service group` in the output) + +# Port-forward postgresql to localhost +github.com/kraftcloud/examples/postgres$ kraft cloud tunnel 5432:5432 + + +$ psql -U postgres -h localhost +Password for user postgres: unikraft +psql (16.2) +Type "help" for help. + +postgres=# CREATE TABLE contacts (id SERIAL PRIMARY KEY, name TEXT, email TEXT); +CREATE TABLE +postgres=# + + +``` + +## Deploy the backend: + +```console +github.com/kraftcloud/examples/go-postgres-react/go$ kraft cloud deploy --metro fra0 -p 443:8080 . +(Search for `domain` in the output) + +# Ensure that the backend API works fine by talking to the db +$ curl -vv DOMAIN_FROM_ABOVE/contacts +null +``` diff --git a/go-postgres-react/go/server.go b/go-postgres-react/go/server.go index c76afc71..cbfab888 100644 --- a/go-postgres-react/go/server.go +++ b/go-postgres-react/go/server.go @@ -20,7 +20,7 @@ func main() { var err error db, err = sql.Open( "postgres", - "user=yourusername dbname=yourdbname sslmode=disable", + "user=postgres dbname=postgres password=unikraft host=postgres-wahr0.internal sslmode=disable", ) if err != nil { panic(err) From 575a3c6035860941717608fb21b664f6a4cc55ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sankar=20=E0=AE=9A=E0=AE=99=E0=AF=8D=E0=AE=95=E0=AE=B0?= =?UTF-8?q?=E0=AF=8D?= Date: Fri, 31 May 2024 18:20:00 +0530 Subject: [PATCH 3/4] Update instructions for db confirmation step --- go-postgres-react/README.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/go-postgres-react/README.md b/go-postgres-react/README.md index 8eadeaae..f1353a7d 100644 --- a/go-postgres-react/README.md +++ b/go-postgres-react/README.md @@ -63,6 +63,30 @@ github.com/kraftcloud/examples/go-postgres-react/go$ kraft cloud deploy --metro (Search for `domain` in the output) # Ensure that the backend API works fine by talking to the db -$ curl -vv DOMAIN_FROM_ABOVE/contacts + +# Empty response first +$ curl -vv https://DOMAIN_FROM_ABOVE.fra0.kraft.host/contacts null + +# Create contact next +$ curl -v https://DOMAIN_FROM_ABOVE.fra0.kraft.host/contacts -d '{ "name": "example1", "email": "one@example.com" }' + +# Ensure the new contact is saved and retrieved from db via the backend +$ curl https://DOMAIN_FROM_ABOVE.fra0.kraft.host/contacts +[{"name":"example1","email":"one@example.com"}] + +# Above backend API confirms data is saved, but let us check in DB also +$ psql -U postgres -h localhost +Password for user postgres: unikraft +psql (16.2) +Type "help" for help. + +postgres=# select * from contacts; + id | name | email +----+----------+----------------- + 1 | example1 | one@example.com +(1 row) + +postgres=# + ``` From 9435b388c69d0ebc303042b1913c9ebc15476418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sankar=20=E0=AE=9A=E0=AE=99=E0=AF=8D=E0=AE=95=E0=AE=B0?= =?UTF-8?q?=E0=AF=8D?= Date: Fri, 31 May 2024 18:27:57 +0530 Subject: [PATCH 4/4] markdown cleanups --- go-postgres-react/README.md | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/go-postgres-react/README.md b/go-postgres-react/README.md index f1353a7d..8b307680 100644 --- a/go-postgres-react/README.md +++ b/go-postgres-react/README.md @@ -2,36 +2,13 @@ This is for creating a Contacts application with the following components: -- a Golang backend -- a Postgresql database for saving data - -- the corresponding Volume for persistent storage -- a react frontend app for serving the UI +- [x] a Golang backend +- [x] a Postgresql database for saving data + -- the corresponding Volume for persistent storage +- [] a react frontend app for serving the UI ## Create a volume and deploy postgresql -``` -❯ kraft cloud deploy --metro fra0 -M 1024 -e POSTGRES_PASSWORD=unikraft -e PGDATA=/volume/postgres -v postgres:/volume -p 5432:5432/tls . - W could not parse image name: invalid reference format: repository name must be lowercase -[+] building rootfs... done! x86_64 [24.3s] -[+] packaging index.unikraft.io/sp/postgres:latest... done! kraftcloud/x86_64 [0.2s] -[+] pushing index.unikraft.io/sp/postgres:latest (kraftcloud/x86_64)... done! [50.3s] - -[●] Deployed successfully! - │ - ├────────── name: postgres-wahr0 - ├────────── uuid: 51095ece-2c34-4ec7-85c9-af0be864c91a - ├───────── state: running - ├──────── domain: cool-sound-5t2t69gg.fra0.kraft.host - ├───────── image: sp/postgres@sha256:944874221c4fb0bd5a617e5e32b05415db071d4bd964eaca822989f772fa3083 - ├───── boot time: 617.25 ms - ├──────── memory: 1024 MiB - ├─ service group: cool-sound-5t2t69gg - ├── private fqdn: postgres-wahr0.internal - ├──── private ip: 172.18.175.4 - └────────── args: wrapper.sh docker-entrypoint.sh postgres - -``` - ```console $ cd github.com/kraftcloud/examples/postgres