Skip to content

Commit

Permalink
Add multi and arm dockerfiles (#265)
Browse files Browse the repository at this point in the history
* Add multi and arm dockerfiles

* Update multi dockerfile to remove duplicate code

* Changes for blueprint build

* Addressing comments, documentation changes

* Fix whitespace

* Fix newlines

---------

Co-authored-by: Lauren Datz <105828115+ladatz@users.noreply.github.com>
  • Loading branch information
devkelley and ladatz authored Mar 11, 2024
1 parent 8b3789b commit ad58e6c
Show file tree
Hide file tree
Showing 7 changed files with 352 additions and 9 deletions.
5 changes: 0 additions & 5 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,3 @@ target/
devops/
docs/
tools/

Cargo.lock

**/Dockerfile
**/Dockerfile.**
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ ARG CHARIOTT_UID=10001
RUN apt update && apt upgrade -y
RUN apt install -y cmake protobuf-compiler

WORKDIR /sdv

COPY ./ .

# Check that CHARIOTT_UID argument is valid.
RUN /sdv/container/scripts/argument_sanitizer.sh \
--arg-value "${CHARIOTT_UID}" \
--regex "^[0-9]+$" || \
( echo "Argument sanitizer failed for ARG 'CHARIOTT_UID'"; exit 1 )

# unprivileged identity to run Chariott Service Discovery as
RUN adduser \
--disabled-password \
Expand All @@ -27,10 +37,6 @@ RUN adduser \
--uid "${CHARIOTT_UID}" \
chariott

WORKDIR /sdv

COPY ./ .

RUN rustup target add x86_64-unknown-linux-musl

RUN cargo build --release --target=x86_64-unknown-linux-musl -p service_discovery
Expand Down
62 changes: 62 additions & 0 deletions Dockerfile.service_discovery.arm64
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
# SPDX-License-Identifier: MIT

ARG RUST_VERSION=1.70

FROM docker.io/library/rust:${RUST_VERSION} AS builder

# Dockerfile for building Eclipse Chariott Service Discovery container
#
# This Dockerfile utilizes a two step build process. It builds Chariott
# Service Discovery with statically linked dependencies (using musl)
# for an arm64 architecture.

# Chariott user id
ARG CHARIOTT_UID=10001

RUN apt update && apt upgrade -y
RUN apt install -y cmake protobuf-compiler gcc-aarch64-linux-gnu

WORKDIR /sdv

COPY ./ .

# Check that UID argument is valid.
RUN /sdv/container/scripts/argument_sanitizer.sh \
--arg-value "${UID}" \
--regex "^[0-9]+$" || \
( echo "Argument sanitizer failed for ARG 'UID'"; exit 1 )

# unprivileged identity to run Chariott Service Discovery as
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${CHARIOTT_UID}" \
chariott

RUN rustup target add aarch64-unknown-linux-musl

RUN cargo build --release --target=aarch64-unknown-linux-musl -p service_discovery

####################################################################################################
## Final image
####################################################################################################
FROM arm64v8/alpine:latest

# Import Chariott user and group from builder.
COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /etc/group /etc/group

WORKDIR /sdv

# Copy our build
COPY --from=builder /sdv/target/aarch64-unknown-linux-musl/release/service_discovery /sdv/service_discovery

# Use the unprivileged chariott user during execution.
USER chariott:chariott

CMD ["./service_discovery"]
81 changes: 81 additions & 0 deletions Dockerfile.service_discovery.multi
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
# SPDX-License-Identifier: MIT

ARG RUST_VERSION=1.70

FROM --platform=$BUILDPLATFORM docker.io/library/rust:${RUST_VERSION} AS builder

# Dockerfile for building Eclipse Chariott Service Discovery container
#
# This Dockerfile utilizes a two step build process. It builds Chariott
# Service Discovery with statically linked dependencies (using musl)
# for a x86_64 and aarch64 architecture, based on the TARGETARCH.

# Target architecture to cross-compile
ARG TARGETARCH

# Chariott user id
ARG CHARIOTT_UID=10001

RUN apt update && apt upgrade -y
RUN apt install -y cmake protobuf-compiler

WORKDIR /sdv

COPY ./ .

# Check that CHARIOTT_UID argument is valid.
RUN /sdv/container/scripts/argument_sanitizer.sh \
--arg-value "${CHARIOTT_UID}" \
--regex "^[0-9]+$" || \
( echo "Argument sanitizer failed for ARG 'CHARIOTT_UID'"; exit 1 )

# unprivileged identity to run Chariott Service Discovery as
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${CHARIOTT_UID}" \
chariott

# Check that TARGETARCH argument is valid.
RUN /sdv/container/scripts/argument_sanitizer.sh \
--arg-value "${TARGETARCH}" \
--regex "^[a-zA-Z_0-9-]+$" || \
( echo "Argument sanitizer failed for ARG 'TARGETARCH'"; exit 1 )

# Based on the target architecture, add the appropriate build target and build service.
RUN if [ "$TARGETARCH" = "amd64" ]; then \
CARGOARCH="x86_64-unknown-linux-musl"; \
elif [ "$TARGETARCH" = "arm64" ]; then \
apt install -y gcc-aarch64-linux-gnu; \
CARGOARCH="aarch64-unknown-linux-musl"; \
else \
echo "Unsupported cross-compile architecture"; \
exit 1; \
fi; \
rustup target add ${CARGOARCH}; \
cargo build --release --target=${CARGOARCH} -p service_discovery; \
mkdir -p /sdv/release && cp /sdv/target/${CARGOARCH}/release/service_discovery /sdv/release/service_discovery

####################################################################################################
## Final image
####################################################################################################
FROM --platform=$TARGETPLATFORM alpine:latest

# Import Chariott user and group from builder.
COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /etc/group /etc/group

WORKDIR /sdv

# Copy our build
COPY --from=builder /sdv/release/service_discovery /sdv/service_discovery

# Use the unprivileged chariott user during execution.
USER chariott:chariott

CMD ["./service_discovery"]
138 changes: 138 additions & 0 deletions container/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
## Containers

This repository provides several Dockerfiles to enable building of OCI container images. This
document has instructions for building and running the provided Dockerfiles in
[Docker](#docker-containers) and [Podman](#podman-containers). Refer to the
[Dockerfiles](#dockerfiles) section to select the appropriate Dockerfile.

### Dockerfiles

#### Service Discovery

- [Dockerfile.service_discovery.amd64](../Dockerfile.service_discovery.amd64) - Dockerfile used to build the `Service Discovery Service` for the
x86-64 architecture.
- [Dockerfile.service_discovery.arm64](../Dockerfile.service_discovery.arm64) - Dockerfile used to build the `Service Discovery Service` for the
aarch64 architecture.
- [Dockerfile.service_discovery.multi](../Dockerfile.service_discovery.multi) - Dockerfile used to build the `Service Discovery Service` for multiple architectures based on the TARGETARCH argument.

#### Intent Brokering

- [Dockerfile.intent_brokering.amd64](../Dockerfile.intent_brokering.amd64) - Dockerfile used to build the `Intent Brokering Service` for the
x86-64 architecture.
- [Dockerfile.intent_brokering.arm64](../Dockerfile.intent_brokering.arm64) - Dockerfile used to build the `Intent Brokering Service` for the
aarch64 architecture.

### Docker Containers

#### Prequisites

[Install Docker](https://docs.docker.com/engine/install/)

#### Running in Docker

To run the service in a Docker container:

1. Run the following command in the project root directory to build the docker container from the
Dockerfile:

```shell
docker build -t <image_name> -f <Dockerfile> .
```

For example, to build an image for the `service_discovery` component:

```shell
docker build -t service_discovery -f Dockerfile.service_discovery.amd64 .
```

Or to build a multi-platform image for the `service_discovery` component and push it to a
container registry:
You must first create a new builder using the docker-container driver, which gives you access
to more complex features like multi-platform build. See more information here:
[multi-platform builds.](https://docs.docker.com/build/building/multi-platform/#cross-compilation)

```shell
docker buildx create --name multibuilder --driver docker-container --use
docker buildx build --platform=linux/amd64,linux/arm64 -f Dockerfile.service_discovery.multi -t <container_registry>/service_discovery_multi --push .
```

1. Once the container has been built, start the container in interactive mode with the following
command in the project root directory:

```shell
docker run --name <container_name> --network=host -it --rm <image_name>
```

For example, to run the `service_discovery` image built in step 1:

```shell
docker run --name service_discovery --network=host -it --rm service_discovery
```

>Note: A custom network is recommended when using a container for anything but testing.

1. To detach from the container, enter:

<kbd>Ctrl</kbd> + <kbd>p</kbd>, <kbd>Ctrl</kbd> + <kbd>q</kbd>

1. To stop the container, enter:

```shell
docker stop <container_name>
```

For example, to stop the `service_discovery` container started in step 2:

```shell
docker stop service_discovery
```

### Podman Containers

#### Prequisites

[Install Podman](https://podman.io/docs/installation)

#### Running in Podman

To run the service in a Podman container:

1. Run the following command in the project root directory to build the podman container from the
Dockerfile:

```shell
podman build -t <image_name> -f <Dockerfile> .
```

For example, to build an image for the `service_discovery` component:

```shell
podman build -t service_discovery -f Dockerfile.amd64 .
```

1. Once the container has been built, start the container with the following command in the project
root directory:

```shell
podman run --network=host <image_name>
```

For example, to run the `service_discovery` image built in step 1:

```shell
podman run --network=host service_discovery
```

>Note: A custom network is recommended when using a container for anything but testing.

1. To stop the container, run:

```shell
podman ps -f ancestor=<image_name> --format="{{.Names}}" | xargs podman stop
```

For example, to stop the `service_discovery` container started in step 2:

```shell
podman ps -f ancestor=localhost/service_discovery:latest --format="{{.Names}}" | xargs podman stop
```
61 changes: 61 additions & 0 deletions container/scripts/argument_sanitizer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/bash

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
# SPDX-License-Identifier: MIT

# Exits immediately on failure.
set -eu

# Function to display usage information
usage() {
echo "Usage: $0 [-a|--arg-value] <ARGUMENT_VALUE> [-r|--regex] <ACCEPTED_REGEX>"
echo "Example:"
echo " $0 -a \"\${APP_NAME}\" -r \"^[a-zA-Z_0-9-]+$\""
}

# Parse command line arguments
while [[ $# -gt 0 ]]
do
key="$1"

case $key in
-a|--arg-value)
arg_value="$2"
shift # past argument
shift # past value
;;
-r|--regex)
regex="$2"
shift # past argument
shift # past value
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $key"
usage
exit 1
esac
done

# Check if all required arguments have been set
if [[ -z "${arg_value}" || -z "${regex}" ]]; then
echo "Error: Missing required arguments:"
[[ -z "${arg_value}" ]] && echo " -a|--arg-value"
[[ -z "${regex}" ]] && echo " -r|--regex"
echo -e "\n"
usage
exit 1
fi

sanitized=$(echo "${arg_value}" | tr -dc "${regex}");
[ "$sanitized" = "${arg_value}" ] || {
echo "ARG is invalid. ARG='${arg_value}' sanitized='${sanitized}'";
exit 1
}

echo -e "\nARG with value '${arg_value}' is sanitized"
exit 0

0 comments on commit ad58e6c

Please sign in to comment.