Skip to content

Commit

Permalink
automated commit
Browse files Browse the repository at this point in the history
Signed-off-by: Public copy <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
github-actions[bot] committed Oct 17, 2024
1 parent d118a9f commit 11603a1
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 244 deletions.
2 changes: 1 addition & 1 deletion images/confluent-kafka/tests/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ TEST_produce_consume() {
docker exec "${CONTAINER_NAME}" kafka-topics --create --topic "${TOPIC_NAME}" --partitions "${PARTITIONS}" --replication-factor "${REPLICATION_FACTOR}" --if-not-exists --bootstrap-server kafka-kraft:"${KAFKA_PORT}"

# Produce a test message
echo "Hello Kafka" | docker exec -i "${CONTAINER_NAME}" kafka-console-producer --broker-list kafka-kraft:"${KAFKA_PORT}" --topic "${TOPIC_NAME}"
echo "Hello Kafka" | docker exec -i "${CONTAINER_NAME}" kafka-console-producer --bootstrap-server kafka-kraft:"${KAFKA_PORT}" --topic "${TOPIC_NAME}"

# Consume the message
consumed_message=$(docker exec "${CONTAINER_NAME}" timeout 10 kafka-console-consumer --bootstrap-server kafka-kraft:"${KAFKA_PORT}" --topic "${TOPIC_NAME}" --from-beginning --max-messages 1)
Expand Down
278 changes: 237 additions & 41 deletions images/go/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,97 +32,293 @@ Be sure to replace the `ORGANIZATION` placeholder with the name used for your or
<!--getting:end-->

<!--body:start-->
## Secure-by-default Features
## Compatibility Notes

Where possible, the Go Chainguard Image is built for compatibility with the [Docker official image for Golang](https://hub.docker.com/_/golang/).

The Go Chainguard Image uses the `glibc` implementation of the C standard library, while the Alpine version of the Golang official Docker Image uses `musl`. See our [article on glibc vs. musl](https://edu.chainguard.dev/chainguard/chainguard-images/working-with-images/images-compiled-programs/glibc-vs-musl/) on Chainguard Academy for an overview of the differences between these implementations.


The examples in this README recommend executing Go binaries from one of our runtime Chainguard Images, such as the `glibc-dynamic` or `static` Chainguard Images. If using the `static` Chainguard Image, make sure to build your Go binary with static linking. In most cases, this requires running `CGO_ENABLED=0 go build` when building the binary. If dynamic linking is needed, use the `glibc-dynamic` Chainguard Image or the Go Chainguard Image to run your application.


In Go 1.20, we default to using the new `GODEBUG` settings of `tarinsecurepath=0` and `zipinsecurepath=0`. These can be disabled by clearing the `GODEBUG` environment variable, or by setting them to `1`.

Learn more about these settings in the [Go release notes](https://tip.golang.org/doc/go1.20).

## Go Application Examples
## Getting Started

This section contains two examples of how you can use the Go Chainguard Image to build an example Go application. For more information on working with this Image, check out our [Getting Started with the Go Chainguard Image](https://edu.chainguard.dev/chainguard/chainguard-images/getting-started/getting-started-go/) guide.
### Example: CLI Application Using Multi-Stage Build

The following build demonstrates a command line application with support for flags and positional arguments. The application prints a modifiable greeting message and provides usage information if the wrong number of arguments are passed by a user or the user passes an unrecognized flag.

### Host architecture example
First, create a project folder and change the working directory to that folder:

Many Image directories in the [public Chainguard Images GitHub repository](https://github.com/chainguard-images/images), including the one for the Go Image, contain examples you can run to test out the given Image.
```sh
mkdir -p ~/go-greeter && cd $_
```

You can build the Go application in [tests/hello/main.go](https://github.com/chainguard-images/images/blob/main/images/go/tests/hello/main.go) using the host architecture of your local machine by cloning the GitHub repository and then navigating to the `/images/go/` directory.
Next, ,write a file defining our Go CLI application (`main.go`:

From there, run the following command:
```sh
cat << 'EOF' > main.go
package main
import (
"flag"
"fmt"
"log"
"os"
)
func usage() {
fmt.Fprintf(os.Stderr, "usage: hello [options] [name]\n")
flag.PrintDefaults()
os.Exit(2)
}
var (
greeting = flag.String("g", "Hello", "Greet with `greeting`")
)
func main() {
// Configure logging
log.SetFlags(0)
log.SetPrefix("hello: ")
// Parse flags.
flag.Usage = usage
flag.Parse()
// Parse and validate arguments.
name := "Linky 🐙"
args := flag.Args()
if len(args) >= 2 {
usage()
}
if len(args) >= 1 {
name = args[0]
}
if name == "" { // hello '' is an error
log.Fatalf("invalid name %q", name)
}
fmt.Printf("%s, %s!\n", *greeting, name)
}
EOF
```

Create a go.mod` file to list dependencies:

```sh
docker run --rm -v "${PWD}:/work" -w /work/tests/hello \
-e GOOS="$(go env GOOS)" -e GOARCH="$(go env GOARCH)" \
cgr.dev/chainguard/go build -o /work/hello .
cat << 'EOF' > go.mod
module chainguard.dev/greet
go 1.19
EOF
```

The example application will be built to `./hello`:
Write a `Dockerfile` to define our image build:

```sh
./hello
cat << 'EOF' > Dockerfile
FROM cgr.dev/chainguard/go AS builder
COPY . /app
RUN cd /app && go build -o go-greeter .
FROM cgr.dev/chainguard/static
COPY --from=builder /app/go-greeter /usr/bin/
ENTRYPOINT ["/usr/bin/go-greeter"]
EOF
```

The `Dockerfile` uses a multi-stage build approach, compiling the application using the `go` Chainguard Image, then copying the binary to the `static` Chainguard Image for execution. Note that the `static` image requires that the Go binary be statically linked—if your application requires dynamic linking, consider using the `glibc-dynamic` Chainguard Image for your runtime (see the second example in this README).

Build the image, tagging it `go-greeter`:

```sh
docker build . -t go-greeter
```

Run the image:

```sh
docker run go-greeter
```

You should see output similar to the following:

```
Hello, Linky 🐙!
```
Hello World!

You can also pass in arguments that will be parsed by the Go CLI application:

```sh
docker run go-greeter -g Greetings "Chainguard user"
```

This will produce the following output:

### Dockerfile example
```
Greetings, Chainguard user!
```

The following example Dockerfile builds a hello-world program in Go and copies it on top of the `cgr.dev/chainguard/static:latest` base image:
The application will also share usage instructions when prompted with the `--help` flag or when invalid flags are passed.

```dockerfile
FROM cgr.dev/chainguard/go:latest as build
Because we used the `static` Chainguard Image as our runtime, the final image only requires a few megabytes on disk:

WORKDIR /work

COPY <<EOF go.mod
module hello
go 1.19
EOF
```sh
docker inspect go-greeter | jq -c 'first' | jq .Size | numfmt --to iec --format "%8.4f"
```

The final size, `3.5055M`, is orders of magnitude smaller than it would be running the application using a Go image. However, if your application is dynamically linked to shared objects, consider using the `glibc-dynamic` Chainguard Image for your runtime or take extra steps to build your Go binary statically.

### Example: Web Application

The following build demonstrates an application that's accessible by HTTP server. The application renders a simple message that changes based on the URI.

First, create a project folder and change the working directory to that folder:

COPY <<EOF main.go
```sh
mkdir -p ~/greet-server && cd $_
```

Next, write a `main.go` file defining our web application:

```sh
cat << 'EOF' > main.go
package main
import "fmt"
import (
"flag"
"fmt"
"html"
"log"
"net/http"
"os"
"runtime/debug"
"strings"
)
func usage() {
fmt.Fprintf(os.Stderr, "usage: helloserver [options]\n")
flag.PrintDefaults()
os.Exit(2)
}
var (
greeting = flag.String("g", "Hello", "Greet with `greeting`")
addr = flag.String("addr", "0.0.0.0:8080", "address to serve")
)
func main() {
fmt.Println("Hello World!")
// Parse flags.
flag.Usage = usage
flag.Parse()
// Parse and validate arguments (none).
args := flag.Args()
if len(args) != 0 {
usage()
}
// Register handlers. for greeting and version
http.HandleFunc("/", greet)
http.HandleFunc("/version", version)
log.Printf("serving http://%s\n", *addr)
log.Fatal(http.ListenAndServe(*addr, nil))
}
EOF
RUN go build -o hello .
FROM cgr.dev/chainguard/static:latest
func version(w http.ResponseWriter, r *http.Request) {
info, ok := debug.ReadBuildInfo()
if !ok {
http.Error(w, "no build information available", 500)
return
}
COPY --from=build /work/hello /hello
CMD ["/hello"]
fmt.Fprintf(w, "<!DOCTYPE html>\n<pre>\n")
fmt.Fprintf(w, "%s\n", html.EscapeString(info.String()))
}
func greet(w http.ResponseWriter, r *http.Request) {
name := strings.Trim(r.URL.Path, "/")
if name == "" {
name = "Linky 🐙"
}
fmt.Fprintf(w, "<!DOCTYPE html>\n")
fmt.Fprintf(w, "%s, %s!\n", *greeting, html.EscapeString(name))
}
EOF
```

Run the following command to build the demo image and tag it as `go-hello-world`:
Next, write a `go.mod` file listing dependencies:

```sh
docker build -t go-hello-world .
cat << 'EOF' > go.mod
module chainguard.dev/greet-server
go 1.19
EOF
```

Now you can run the image with:
Write a `Dockerfile` to define our image build:

```sh
docker run go-hello-world
```
cat << 'EOF' > Dockerfile
FROM cgr.dev/chainguard/go AS builder
COPY . /app
RUN cd /app && go build
FROM cgr.dev/chainguard/glibc-dynamic
COPY --from=builder /app/greet-server /usr/bin/
You should get output like this:
EXPOSE 8080
ENTRYPOINT ["/usr/bin/greet-server"]
EOF
```
Hello World!

The `Dockerfile` uses a multi-stage build approach, compiling the application using the `go` Chainguard Image, then copying the binary to the `glibc-dynamic` Chainguard Image to serve.

Build the image, tagging it `greet-server`:

```sh
docker build . -t greet-server
```

It’s worth noting how small the resulting image is:
Run the image:

```sh
docker images go-hello-world
docker run -p 8080:8080 greet-server
```

Visit [http://0.0.0.0:8080/](http://0.0.0.0:8080/) using a web browser on your host machine. You should see the following:

```
Hello, Linky 🐙!
```

Changes to the URI will be routed to the application. Try visiting [http://0.0.0.0:8080/Chainguard%20Customer](http://0.0.0.0:8080/Chainguard%20Customer). You should see the following output:

```
REPOSITORY TAG IMAGE ID CREATED SIZE
go-hello-world latest 859fedabd532 5 hours ago 3.21MB
Hello, Chainguard Customer!
```

The application will also share version information at [http://0.0.0.0:8080/version](http://0.0.0.0:8080/version).

If you're building a web application with Go, consider the [nginx](https://images.chainguard.dev/directory/image/nginx/overview) Chainguard Image for use as a reverse proxy.

## Documentation and Resources

- [Chainguard Academy: Getting Started with the Go Chainguard Image](https://edu.chainguard.dev/chainguard/chainguard-images/getting-started/go/)
- [Video: Migrating a Dockerfile for a Go application to use Chainguard Images](https://edu.chainguard.dev/chainguard/chainguard-images/videos/migrating_go/)
- [Blog Post: Statically Linking Go in 2022](https://mt165.co.uk/blog/static-link-go/)
- [Blog Post: Building minimal and low CVE images for compiled languages](https://www.chainguard.dev/unchained/building-minimal-and-low-cve-images-for-compiled-languages)
- [Chainguard Academy: glibc vs. musl](https://edu.chainguard.dev/chainguard/chainguard-images/working-with-images/images-compiled-programs/glibc-vs-musl/)
<!--body:end-->

## Contact Support
Expand Down
10 changes: 5 additions & 5 deletions images/keycloak-operator/tests/keycloak-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ TEST_keycloak_api() {
return 1
fi

# Ensure that an 'admin' user was returned in the API response.
extracted_username=$(echo "${users_output}" | jq -r '.[] | select(.username=="admin") | .username')
if [[ "${extracted_username}" == "admin" ]]; then
echo "Keycloak API correctly returned 'admin' user details."
# Ensure that a 'temp-admin' user was returned in the API response.
extracted_username=$(echo "${users_output}" | jq -r '.[] | select(.username=="temp-admin") | .username')
if [[ "${extracted_username}" == "temp-admin" ]]; then
echo "Keycloak API correctly returned 'temp-admin' user details."
else
echo "FAILED: No entry with username 'admin' found in the response: ${users_output}"
echo "FAILED: No entry with username 'temp-admin' found in the response: ${users_output}"
exit 1
fi
}
Expand Down
Loading

0 comments on commit 11603a1

Please sign in to comment.