-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
488 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
name: Docker Build and Push Gateway Images | ||
on: | ||
push: | ||
branches: | ||
- main | ||
- fix-ci | ||
pull_request: | ||
|
||
permissions: write-all | ||
|
||
jobs: | ||
build-push-gateway: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
application: [adapter, dataManager, AlerteDetector, pre-treatment, transmitter] | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
- name: Set up QEMU | ||
uses: docker/setup-qemu-action@v3 | ||
- name: Set up Docker Buildx | ||
uses: docker/setup-buildx-action@v3 | ||
- name: Login to GitHub Container Registry | ||
uses: docker/login-action@v1 | ||
with: | ||
registry: ghcr.io | ||
username: ${{ github.actor }} | ||
password: ${{ secrets.GITHUB_TOKEN }} | ||
- name: downcase REPO name as output | ||
id: downcase | ||
run: | | ||
echo "::set-output name=downcase::$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" | ||
- name: Build and push api image | ||
uses: docker/build-push-action@v5 | ||
with: | ||
platforms: linux/amd64,linux/arm64 | ||
push: true | ||
context: gateway/${{ matrix.application }} | ||
tags: ghcr.io/${{ steps.downcase.outputs.downcase }}/gateway-${{ matrix.application }}:${{ github.sha }}, ghcr.io/${{ steps.downcase.outputs.downcase }}/gateway-${{ matrix.application }}:${{ github.ref_name }} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Stage 1: Build Stage | ||
# Use a specific version of the official Golang image as the base image | ||
FROM golang:1.22-bullseye AS build | ||
|
||
# Create a non-root user for running the application | ||
RUN useradd -u 1001 nonroot | ||
|
||
# Set the working directory inside the container | ||
WORKDIR /app | ||
|
||
# Copy only the go.mod file to install dependencies efficiently and leverage layer caching | ||
COPY go.mod ./ | ||
|
||
# Set the GIN_MODE environment variable to release | ||
ENV GIN_MODE=release | ||
|
||
|
||
# Use cache mounts to speed up the installation of existing dependencies | ||
RUN --mount=type=cache,target=/go/pkg/mod \ | ||
--mount=type=cache,target=/root/.cache/go-build \ | ||
go mod download | ||
|
||
# Copy the entire application source code | ||
COPY . . | ||
|
||
# Compile the application during build and statically link the binary | ||
RUN go build \ | ||
-ldflags="-linkmode external -extldflags -static" \ | ||
-tags netgo \ | ||
-o go-app | ||
|
||
# Stage 2: Deployable Image | ||
# Use a minimal scratch image as the base image for the final image | ||
FROM scratch | ||
|
||
# Copy the /etc/passwd file from the build stage to provide non-root user information | ||
COPY --from=build /etc/passwd /etc/passwd | ||
|
||
# Copy the compiled application binary from the build stage to the final image | ||
COPY --from=build /app/go-app /go-app | ||
|
||
# Use the non-root user created in the build stage | ||
USER nonroot | ||
|
||
|
||
# Define the command to run the application when the container starts | ||
CMD ["./go-app"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Stage 1: Build Stage | ||
# Use a specific version of the official Golang image as the base image | ||
FROM golang:1.22-bullseye AS build | ||
|
||
# Create a non-root user for running the application | ||
RUN useradd -u 1001 nonroot | ||
|
||
# Set the working directory inside the container | ||
WORKDIR /app | ||
|
||
# Copy only the go.mod file to install dependencies efficiently and leverage layer caching | ||
COPY go.mod ./ | ||
|
||
# Set the GIN_MODE environment variable to release | ||
ENV GIN_MODE=release | ||
|
||
|
||
# Use cache mounts to speed up the installation of existing dependencies | ||
RUN --mount=type=cache,target=/go/pkg/mod \ | ||
--mount=type=cache,target=/root/.cache/go-build \ | ||
go mod download | ||
|
||
# Copy the entire application source code | ||
COPY . . | ||
|
||
# Compile the application during build and statically link the binary | ||
RUN go build \ | ||
-ldflags="-linkmode external -extldflags -static" \ | ||
-tags netgo \ | ||
-o go-app | ||
|
||
# Stage 2: Deployable Image | ||
# Use a minimal scratch image as the base image for the final image | ||
FROM scratch | ||
|
||
# Copy the /etc/passwd file from the build stage to provide non-root user information | ||
COPY --from=build /etc/passwd /etc/passwd | ||
|
||
# Copy the compiled application binary from the build stage to the final image | ||
COPY --from=build /app/go-app /go-app | ||
|
||
# Use the non-root user created in the build stage | ||
USER nonroot | ||
|
||
|
||
# Define the command to run the application when the container starts | ||
CMD ["./go-app"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,47 @@ | ||
# Stage 1: Build Stage | ||
# Use a specific version of the official Golang image as the base image | ||
FROM golang:1.22-bullseye AS build | ||
|
||
FROM golang:1.23 | ||
# Create a non-root user for running the application | ||
RUN useradd -u 1001 nonroot | ||
|
||
# Set destination for COPY | ||
WORKDIR /app | ||
# Set the working directory inside the container | ||
WORKDIR /app | ||
|
||
# Download Go modules | ||
COPY go.mod go.sum ./ | ||
RUN go mod download | ||
# Copy only the go.mod file to install dependencies efficiently and leverage layer caching | ||
COPY go.mod ./ | ||
|
||
# Copy the source code. Note the slash at the end, as explained in | ||
# https://docs.docker.com/reference/dockerfile/#copy | ||
COPY *.go ./ | ||
# Set the GIN_MODE environment variable to release | ||
ENV GIN_MODE=release | ||
|
||
# Build | ||
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/batch-send | ||
|
||
# Run the compiled binary | ||
CMD ["/app/batch-send"] | ||
# Use cache mounts to speed up the installation of existing dependencies | ||
RUN --mount=type=cache,target=/go/pkg/mod \ | ||
--mount=type=cache,target=/root/.cache/go-build \ | ||
go mod download | ||
|
||
# Copy the entire application source code | ||
COPY . . | ||
|
||
# Compile the application during build and statically link the binary | ||
RUN go build \ | ||
-ldflags="-linkmode external -extldflags -static" \ | ||
-tags netgo \ | ||
-o go-app | ||
|
||
# Stage 2: Deployable Image | ||
# Use a minimal scratch image as the base image for the final image | ||
FROM scratch | ||
|
||
# Copy the /etc/passwd file from the build stage to provide non-root user information | ||
COPY --from=build /etc/passwd /etc/passwd | ||
|
||
# Copy the compiled application binary from the build stage to the final image | ||
COPY --from=build /app/go-app /go-app | ||
|
||
# Use the non-root user created in the build stage | ||
USER nonroot | ||
|
||
|
||
# Define the command to run the application when the container starts | ||
CMD ["./go-app"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"fmt" | ||
"github.com/gogo/protobuf/proto" | ||
"github.com/golang/snappy" | ||
"github.com/prometheus/prometheus/prompb" | ||
"io" | ||
"net/http" | ||
"time" | ||
) | ||
|
||
type TimeSeries struct { | ||
Labels []Label | ||
Sample []Sample | ||
} | ||
|
||
type Label struct { | ||
Name string | ||
Value string | ||
} | ||
|
||
type Sample struct { | ||
Time time.Time | ||
Value float64 | ||
} | ||
|
||
// ClientOption is used to set custom client options. | ||
type ClientOption func(opts *clientOptions) | ||
|
||
// HttpClient option allows configuring custom HTTP client. | ||
func HttpClient(client *http.Client) ClientOption { | ||
return func(opts *clientOptions) { | ||
opts.httpClient = client | ||
} | ||
} | ||
|
||
type clientOptions struct { | ||
httpClient *http.Client | ||
} | ||
|
||
func NewClient(endpoint string, options ...ClientOption) *Client { | ||
opts := clientOptions{ | ||
httpClient: &http.Client{Timeout: 30 * time.Second}, | ||
} | ||
for _, opt := range options { | ||
opt(&opts) | ||
} | ||
p := &Client{ | ||
endpoint: endpoint, | ||
opts: &opts, | ||
} | ||
return p | ||
} | ||
|
||
// Client is Prometheus Remote Write client. | ||
type Client struct { | ||
endpoint string | ||
opts *clientOptions | ||
} | ||
|
||
type WriteOption func(opts *writeOptions) | ||
|
||
// WriteHeaders allows passing custom HTTP headers. Once common use case is to pass `X-Scope-OrgID` header for Cortex tenant. | ||
func WriteHeaders(headers map[string]string) WriteOption { | ||
return func(opt *writeOptions) { | ||
opt.headers = headers | ||
} | ||
} | ||
|
||
type writeOptions struct { | ||
headers map[string]string | ||
} | ||
|
||
type WriteRequest struct { | ||
TimeSeries []TimeSeries | ||
} | ||
|
||
type WriteResponse struct { | ||
} | ||
|
||
// Write sends HTTP requests to Prometheus Remote Write compatible API endpoint including Prometheus, Cortex and VictoriaMetrics. | ||
func (p *Client) Write(ctx context.Context, req *WriteRequest, options ...WriteOption) (*WriteResponse, error) { | ||
opts := writeOptions{} | ||
for _, opt := range options { | ||
opt(&opts) | ||
} | ||
// Marshal proto and compress. | ||
pbBytes, err := proto.Marshal(&prompb.WriteRequest{ | ||
Timeseries: toProtoTimeSeries(req.TimeSeries), | ||
}) | ||
if err != nil { | ||
return nil, fmt.Errorf("promwrite: marshaling remote write request proto: %w", err) | ||
} | ||
|
||
compressedBytes := snappy.Encode(nil, pbBytes) | ||
|
||
// Prepare http request. | ||
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, p.endpoint, bytes.NewBuffer(compressedBytes)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
httpReq.Header.Add("X-Prometheus-Remote-Write-Version", "0.1.0") | ||
httpReq.Header.Add("Content-Encoding", "snappy") | ||
httpReq.Header.Set("Content-Type", "application/x-protobuf") | ||
for k, v := range opts.headers { | ||
httpReq.Header.Add(k, v) | ||
} | ||
|
||
// Send http request. | ||
httpResp, err := p.opts.httpClient.Do(httpReq) | ||
if err != nil { | ||
return nil, fmt.Errorf("promwrite: sending remote write request: %w", err) | ||
} | ||
defer httpResp.Body.Close() | ||
|
||
if st := httpResp.StatusCode; st/100 != 2 { | ||
msg, _ := io.ReadAll(httpResp.Body) | ||
return nil, &WriteError{ | ||
err: fmt.Errorf("promwrite: expected status %d, got %d: %s", http.StatusOK, st, string(msg)), | ||
code: st, | ||
} | ||
} | ||
return &WriteResponse{}, nil | ||
} | ||
|
||
func toProtoTimeSeries(timeSeries []TimeSeries) []prompb.TimeSeries { | ||
res := make([]prompb.TimeSeries, len(timeSeries)) | ||
for i, ts := range timeSeries { | ||
labels := make([]prompb.Label, len(ts.Labels)) | ||
for j, lb := range ts.Labels { | ||
labels[j] = prompb.Label{ | ||
Name: lb.Name, | ||
Value: lb.Value, | ||
} | ||
} | ||
pbTs := prompb.TimeSeries{ | ||
Labels: labels, | ||
Samples: toProtoSamples(ts.Sample), | ||
} | ||
res[i] = pbTs | ||
} | ||
return res | ||
} | ||
|
||
func toProtoSamples(sample []Sample) []prompb.Sample { | ||
res := make([]prompb.Sample, len(sample)) | ||
for i, s := range sample { | ||
res[i] = prompb.Sample{ | ||
Timestamp: s.Time.UnixNano() / int64(time.Millisecond), | ||
Value: s.Value, | ||
} | ||
} | ||
return res | ||
} | ||
|
||
// WriteError returned if HTTP call is finished with response status code, but it was not successful. | ||
type WriteError struct { | ||
err error | ||
code int | ||
} | ||
|
||
func (e *WriteError) Error() string { | ||
return e.err.Error() | ||
} | ||
|
||
func (e *WriteError) StatusCode() int { | ||
return e.code | ||
} |
Oops, something went wrong.