Skip to content

Commit

Permalink
merge: #10007 #10012
Browse files Browse the repository at this point in the history
10007: Add OCI & OpenShift labels to Docker image r=npepinpe a=npepinpe

## Description

This PR adds labels to the Docker image following the OCI and OpenShift specs. This includes modifications to the build process to inject the few values which are dynamic, namely:
  - the created at ISO 8601 timestamp
  - the commit SHA (or revision) of the artifact
  - the semantic version of the artifact

You can find the specs here:

- https://github.com/opencontainers/image-spec/blob/main/annotations.md
- https://docs.openshift.com/container-platform/4.10/openshift_images/create-images.html#images-create-metadata_create-images

On top of adding labels, this modifies the `Dockerfile` a bit and pins the production image to specific sha of the base image, ensuring reproducible builds. In the future we should update this sha when need be, and update the golden file (`docker/test/docker-labels.golden.json`).

This also adds `hadolint` to lint our Dockerfile and applies some of the recommendations to it. A new code quality job is added, `Docker checks`, which runs hadolint and verifies that the labels are as expected. The verification is done via a bash script which grabs the labels from a `docker inspect`, and compares it with an interpolated golden file (since we have a few dynamic values). The comparison is done using `diff`, so the output should be familiar to most.

## Related issues

related to #9940 
blocks #10013 



10012: refactor: let `dist` build the actor scheduler for gateway r=oleschoenburg a=oleschoenburg

## Description

This moves the responsibility of creating an actor scheduler for the gateway to the `dist` module. As an added benefit, this allows us to remove some redundant constructors, simplify BrokerClient to never start the actor scheduler and a deprecated method from `BrokerStartupContext`.

## Related issues

<!-- Which issues are closed by this PR or are related -->

relates to #9996 



Co-authored-by: Nicolas Pepin-Perreault <nicolas.pepin-perreault@camunda.com>
Co-authored-by: Ole Schönburg <ole.schoenburg@gmail.com>
  • Loading branch information
3 people committed Aug 5, 2022
3 parents e751fd6 + b447062 + e7b153d commit c017448
Show file tree
Hide file tree
Showing 20 changed files with 284 additions and 133 deletions.
4 changes: 2 additions & 2 deletions .ci/scripts/distribution/ensure-naming-for-process.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/bin/bash -eu

FIND_OUTPUT=$(find . -iname '*workflow*' -not -path '.*/node_modules/*' -not -path '.*/target/*' -not -path '.*/.git/*' -not -path '.*/.github/*' -not -path '.*/vendor/*')
FIND_OUTPUT=$(find . -iname '*workflow*' -not -path '.*/node_modules/*' -not -path '.*/target/*' -not -path '.*/.git/*' -not -path '.*/.github/*' -not -path '.*/vendor/*' -not -path '.*/docker/*')

# if grep doesn't find a match it exits with 1, which we ignore as we check the output later
GREP_OUTPUT=$(grep --exclude-dir={.git,node_modules,target,.ci,.github,vendor} -i -P 'workflow(?![-\s]+(?i)engine)' -r . || true)
GREP_OUTPUT=$(grep --exclude-dir={.git,node_modules,target,.ci,.github,vendor,docker} --exclude="Dockerfile" -i -P 'workflow(?![-\s]+(?i)engine)' -r . || true)

if [ -n "${FIND_OUTPUT}" ] || [ -n "${GREP_OUTPUT}" ]; then
echo "Found occurence of workflow in file names or content"
Expand Down
51 changes: 51 additions & 0 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,54 @@ jobs:
java-version: '17'
- run: mvn -B -D skipTests -D skipChecks install
- run: mvn -T1C -B -D skipTests -P !autoFormat,checkFormat,spotbugs verify
docker-checks:
name: Docker checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: hadolint/hadolint-action@v2.1.0
with:
config: ./.hadolint.yaml
dockerfile: ./Dockerfile
format: sarif
output-file: ./hadolint.sarif
no-color: true
- name: Upload Hadolint Results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: ./hadolint.sarif
- uses: actions/setup-java@v3.4.1
with:
distribution: 'temurin'
java-version: '17'
- uses: stCarolas/setup-maven@v4.4
with:
maven-version: 3.8.5
- name: Package Zeebe
run: mvn -B -DskipTests -DskipChecks package -T1C
- name: Set project version
run: echo ::set-output name=result::$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
id: get-version
- name: Get build timestamp
id: get-date
run: echo "::set-output name=result::$(date --iso-8601=seconds)"
- name: Build Docker image
uses: docker/build-push-action@v3
with:
context: .
# give it a fake registry to make sure we don't accidentally push it
tags: localhost:5000/camunda/zeebe:${{ steps.get-version.outputs.result }}
load: true
no-cache: true
build-args: |
DISTBALL=dist/target/camunda-zeebe-${{ steps.get-version.outputs.result }}.tar.gz
DATE=${{ steps.get-date.outputs.result }}
REVISION=${{ github.sha }}
VERSION=${{ steps.get-version.outputs.result }}
target: app
- name: Verify Docker image
env:
DATE: ${{ steps.get-date.outputs.result }}
REVISION: ${{ github.sha }}
VERSION: ${{ steps.get-version.outputs.result }}
run: ${PWD}/docker/test/verify.sh 'localhost:5000/camunda/zeebe:${{ steps.get-version.outputs.result }}'
14 changes: 12 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,13 @@ jobs:
run: ./build.sh
working-directory: clients/go/cmd/zbctl
- name: Package Zeebe
run: mvn -B -DskipTests -DskipChecks package
run: mvn -B -DskipTests -DskipChecks package -T1C
- name: Set project version
run: echo ::set-output name=result::$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
id: get-version
- name: Get build timestamp
id: get-date
run: echo "::set-output name=result::$(date --iso-8601=seconds)"
- name: Login to DockerHub
uses: docker/login-action@v2
with:
Expand All @@ -90,7 +96,11 @@ jobs:
tags: camunda/zeebe:SNAPSHOT
push: true
no-cache: true
build-args: DISTBALL=dist/target/camunda-zeebe-*-SNAPSHOT.tar.gz
build-args: |
DISTBALL=dist/target/camunda-zeebe-${{ steps.get-version.outputs.result }}.tar.gz
DATE=${{ steps.get-date.outputs.result }}
REVISION=${{ github.sha }}
VERSION=${{ steps.get-version.outputs.result }}
target: app

notify-if-failed:
Expand Down
3 changes: 3 additions & 0 deletions .hadolint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
failure-threshold: warning
format: tty
ignored: []
52 changes: 42 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
ARG APP_ENV=prod
# Override this based on the architecture; this is currently pointing to amd64
ARG BASE_SHA="fce37e5146419a158c2199c6089fa39b92445fb2e66dc0331f8591891239ea3b"

# Building builder image
FROM ubuntu:focal as builder
Expand All @@ -12,28 +14,58 @@ COPY ${DISTBALL} ${TMP_ARCHIVE}
RUN mkdir -p ${TMP_DIR} && \
tar xfvz ${TMP_ARCHIVE} --strip 1 -C ${TMP_DIR} && \
# already create volume dir to later have correct rights
mkdir ${TMP_DIR}/data

RUN apt-get update && \
apt-get install tini && \
mkdir ${TMP_DIR}/data && \
apt-get -qq update && \
apt-get install -y --no-install-recommends tini=0.18.0-1 && \
cp /usr/bin/tini ${TMP_DIR}/bin/tini

COPY docker/utils/startup.sh ${TMP_DIR}/bin/startup.sh
RUN chmod +x -R ${TMP_DIR}/bin/
RUN chmod 0775 ${TMP_DIR} ${TMP_DIR}/data
RUN chmod +x -R ${TMP_DIR}/bin/ && \
chmod 0775 ${TMP_DIR} ${TMP_DIR}/data

# Building prod image
FROM eclipse-temurin:17-jre-focal as prod
FROM eclipse-temurin:17-jre-focal@sha256:${BASE_SHA} as prod

# leave unset to use the default value at the top of the file
ARG BASE_SHA

LABEL org.opencontainers.image.base.digest="${BASE_SHA}"
LABEL org.opencontainers.image.base.name="docker.io/library/eclipse-temurin:17-jre-focal"

# Building dev image
FROM eclipse-temurin:17-jdk-focal as dev
RUN echo "running DEV pre-install commands"
RUN apt-get update
RUN curl -sSL https://github.com/jvm-profiling-tools/async-profiler/releases/download/v1.7.1/async-profiler-1.7.1-linux-x64.tar.gz | tar xzv
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN echo "running DEV pre-install commands" && \
curl -sSL https://github.com/jvm-profiling-tools/async-profiler/releases/download/v1.7.1/async-profiler-1.7.1-linux-x64.tar.gz | tar xzv

# Building application image
# hadolint ignore=DL3006
FROM ${APP_ENV} as app

ARG VERSION=""
ARG DATE=""
ARG REVISION=""

# OCI labels: https://github.com/opencontainers/image-spec/blob/main/annotations.md
LABEL org.opencontainers.image.created="${DATE}"
LABEL org.opencontainers.image.authors="zeebe@camunda.com"
LABEL org.opencontainers.image.url="https://zeebe.io"
LABEL org.opencontainers.image.documentation="https://docs.camunda.io/docs/self-managed/zeebe-deployment/"
LABEL org.opencontainers.image.source="https://github.com/camunda/zeebe"
LABEL org.opencontainers.image.version="${VERSION}"
LABEL org.opencontainers.image.revision="${REVISION}"
LABEL org.opencontainers.image.vendor="Camunda Services GmbH"
LABEL org.opencontainers.image.licenses="(Apache-2.0 AND LicenseRef-Zeebe-Community-1.1)"
LABEL org.opencontainers.image.title="Zeebe"
LABEL org.opencontainers.image.description="Workflow engine for microservice orchestration"

# OpenShift labels: https://docs.openshift.com/container-platform/4.10/openshift_images/create-images.html#defining-image-metadata
LABEL io.openshift.tags="bpmn,orchestration,workflow"
LABEL io.k8s.description="Workflow engine for microservice orchestration"
LABEL io.openshift.non-scalable="false"
LABEL io.openshift.min-memory="512Mi"
LABEL io.openshift.min-cpu="1"

ENV ZB_HOME=/usr/local/zeebe \
ZEEBE_BROKER_GATEWAY_NETWORK_HOST=0.0.0.0 \
ZEEBE_STANDALONE_GATEWAY=false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import io.camunda.zeebe.broker.transport.adminapi.AdminApiRequestHandler;
import io.camunda.zeebe.broker.transport.commandapi.CommandApiServiceImpl;
import io.camunda.zeebe.protocol.impl.encoding.BrokerInfo;
import io.camunda.zeebe.scheduler.ActorScheduler;
import io.camunda.zeebe.scheduler.ActorSchedulingService;
import io.camunda.zeebe.scheduler.ConcurrencyControl;
import io.camunda.zeebe.transport.impl.AtomixServerTransport;
Expand All @@ -42,9 +41,6 @@ public interface BrokerStartupContext {

ActorSchedulingService getActorSchedulingService();

@Deprecated // use getActorSchedulingService instead
ActorScheduler getActorScheduler();

ConcurrencyControl getConcurrencyControl();

BrokerHealthCheckService getHealthCheckService();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import io.camunda.zeebe.broker.transport.adminapi.AdminApiRequestHandler;
import io.camunda.zeebe.broker.transport.commandapi.CommandApiServiceImpl;
import io.camunda.zeebe.protocol.impl.encoding.BrokerInfo;
import io.camunda.zeebe.scheduler.ActorScheduler;
import io.camunda.zeebe.scheduler.ActorSchedulingService;
import io.camunda.zeebe.scheduler.ConcurrencyControl;
import io.camunda.zeebe.transport.impl.AtomixServerTransport;
Expand All @@ -37,7 +36,7 @@ public final class BrokerStartupContextImpl implements BrokerStartupContext {
private final BrokerInfo brokerInfo;
private final BrokerCfg configuration;
private final SpringBrokerBridge springBrokerBridge;
private final ActorScheduler actorScheduler;
private final ActorSchedulingService actorScheduler;
private final BrokerHealthCheckService healthCheckService;
private final ExporterRepository exporterRepository;

Expand All @@ -58,7 +57,7 @@ public BrokerStartupContextImpl(
final BrokerInfo brokerInfo,
final BrokerCfg configuration,
final SpringBrokerBridge springBrokerBridge,
final ActorScheduler actorScheduler,
final ActorSchedulingService actorScheduler,
final BrokerHealthCheckService healthCheckService,
final ExporterRepository exporterRepository,
final List<PartitionListener> additionalPartitionListeners) {
Expand Down Expand Up @@ -92,11 +91,6 @@ public ActorSchedulingService getActorSchedulingService() {
return actorScheduler;
}

@Override
public ActorScheduler getActorScheduler() {
return actorScheduler;
}

@Override
public ConcurrencyControl getConcurrencyControl() {
return concurrencyControl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ void startupInternal(

final var clusterServices = brokerStartupContext.getClusterServices();

@SuppressWarnings("resource")
final var embeddedGatewayService =
new EmbeddedGatewayService(
brokerStartupContext.getBrokerConfiguration(),
brokerStartupContext.getActorScheduler(),
brokerStartupContext.getActorSchedulingService(),
clusterServices.getMessagingService(),
clusterServices.getMembershipService(),
clusterServices.getEventService());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import io.camunda.zeebe.gateway.impl.broker.BrokerClient;
import io.camunda.zeebe.gateway.impl.broker.BrokerClientImpl;
import io.camunda.zeebe.gateway.impl.configuration.GatewayCfg;
import io.camunda.zeebe.scheduler.ActorScheduler;
import io.camunda.zeebe.scheduler.ActorSchedulingService;
import io.camunda.zeebe.scheduler.future.ActorFuture;
import java.util.function.Function;

Expand All @@ -24,14 +24,14 @@ public final class EmbeddedGatewayService implements AutoCloseable {

public EmbeddedGatewayService(
final BrokerCfg configuration,
final ActorScheduler actorScheduler,
final ActorSchedulingService actorScheduler,
final MessagingService messagingService,
final ClusterMembershipService membershipService,
final ClusterEventService eventService) {
final Function<GatewayCfg, BrokerClient> brokerClientFactory =
cfg ->
new BrokerClientImpl(
cfg, messagingService, membershipService, eventService, actorScheduler, false);
cfg, messagingService, membershipService, eventService, actorScheduler);
gateway = new Gateway(configuration.getGateway(), brokerClientFactory, actorScheduler);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
* one or more contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright ownership.
* Licensed under the Zeebe Community License 1.1. You may not use this file
* except in compliance with the Zeebe Community License 1.1.
*/
package io.camunda.zeebe.gateway;

import io.camunda.zeebe.gateway.impl.configuration.GatewayCfg;
import io.camunda.zeebe.scheduler.ActorScheduler;
import io.camunda.zeebe.shared.ActorClockConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
final class ActorSchedulerComponent {

private final GatewayCfg config;
private final ActorClockConfiguration clockConfiguration;

@Autowired
public ActorSchedulerComponent(
final GatewayCfg config, final ActorClockConfiguration clockConfiguration) {
this.config = config;
this.clockConfiguration = clockConfiguration;
}

@Bean("actorScheduler")
ActorScheduler createActorSchedulingService() {
return ActorScheduler.newActorScheduler()
.setCpuBoundActorThreadCount(config.getThreads().getManagementThreads())
.setIoBoundActorThreadCount(0)
.setSchedulerName("gateway-scheduler")
.setActorClock(clockConfiguration.getClock())
.build();
}
}
21 changes: 4 additions & 17 deletions dist/src/main/java/io/camunda/zeebe/gateway/StandaloneGateway.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import io.camunda.zeebe.gateway.impl.broker.cluster.BrokerTopologyManager;
import io.camunda.zeebe.gateway.impl.configuration.GatewayCfg;
import io.camunda.zeebe.scheduler.ActorScheduler;
import io.camunda.zeebe.shared.ActorClockConfiguration;
import io.camunda.zeebe.shared.Profile;
import io.camunda.zeebe.util.CloseableSilently;
import io.camunda.zeebe.util.VersionUtil;
Expand Down Expand Up @@ -51,21 +50,20 @@ public class StandaloneGateway

private final GatewayCfg configuration;
private final SpringGatewayBridge springGatewayBridge;
private final ActorClockConfiguration clockConfig;
private final ActorScheduler actorScheduler;
private final AtomixCluster atomixCluster;

private Gateway gateway;
private ActorScheduler actorScheduler;

@Autowired
public StandaloneGateway(
final GatewayCfg configuration,
final SpringGatewayBridge springGatewayBridge,
final ActorClockConfiguration clockConfig,
final ActorScheduler actorScheduler,
final AtomixCluster atomixCluster) {
this.configuration = configuration;
this.springGatewayBridge = springGatewayBridge;
this.clockConfig = clockConfig;
this.actorScheduler = actorScheduler;
this.atomixCluster = atomixCluster;
}

Expand Down Expand Up @@ -93,7 +91,6 @@ public void run(final String... args) throws Exception {
LOG.info("Starting standalone gateway with configuration {}", configuration.toJson());
}

actorScheduler = createActorScheduler(configuration);
gateway = new Gateway(configuration, this::createBrokerClient, actorScheduler);

springGatewayBridge.registerBrokerClientSupplier(gateway::getBrokerClient);
Expand Down Expand Up @@ -149,16 +146,6 @@ private BrokerClient createBrokerClient(final GatewayCfg config) {
atomixCluster.getMessagingService(),
atomixCluster.getMembershipService(),
atomixCluster.getEventService(),
actorScheduler,
false);
}

private ActorScheduler createActorScheduler(final GatewayCfg config) {
return ActorScheduler.newActorScheduler()
.setCpuBoundActorThreadCount(config.getThreads().getManagementThreads())
.setIoBoundActorThreadCount(0)
.setSchedulerName("gateway-scheduler")
.setActorClock(clockConfig.getClock())
.build();
actorScheduler);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,13 @@ private GatewayCfg createGatewayCfg() {

private StandaloneGateway buildGateway(final GatewayCfg gatewayCfg) {
final AtomixComponent clusterComponent = new AtomixComponent(gatewayCfg);
final ActorSchedulerComponent actorSchedulerComponent =
new ActorSchedulerComponent(gatewayCfg, new ActorClockConfiguration(false));

return new StandaloneGateway(
gatewayCfg,
new SpringGatewayBridge(),
new ActorClockConfiguration(false),
actorSchedulerComponent.createActorSchedulingService(),
clusterComponent.createAtomixCluster());
}
}

0 comments on commit c017448

Please sign in to comment.