# Adding Components to the build process
###### tags: `Proposals`
[toc]
## Synopsis
The following instructions complement Akri [Development](https://github.com/deislabs/akri/blob/main/docs/development.md) and assume that you've already created a new Rust project member for Akri (hopefully using a skeleton generated by [Protocol "skeleton-builder:](https://github.com/deislabs/akri/issues/133). This document intends to summarize the multiple, independents steps necessary to get your component building as part of Akri's build process.
## Assumptions
+ A new Akri module written in Rust called `${MEMBER_NAME}` has been created within (a fork of) Akri's GitHub repo
+ `${MEMBER_NAME}` is in `${MEMBER_PATH}`subdirectory (this should be a relative reference omitting `./`).
## Architectures
Akri builds for 3 architectures and these are referenced using different names by different platforms:
|Generic|Rust|Docker|
|-------|----|------|
|AMD64|x86_64|amd64|
|ARM32|armv7|arm32v7|
|ARM64|aarch64|arm64v8|
## Akri `./Cargo.toml`
+ Add `${MEMBER_PATH}` to the list of `member` in Akri's `./Cargo.toml'
+ For convenience (!) match `${MEMBER_PATH}/Cargo.toml` version property to the current Akri version (in `./version.txt`)
+ See [Versioning](#Versioning)
Pseudo-code
```bash
sed \
--in-place \
--regexp-extended \
"s|^members = \[(.*)\]|^members = \[\1\, \"${MEMBER_PATH}\"]|g" \
./Cargo.toml
```
## `.dockerignore`
Akri's Cargo Cross build process generates debug and release binaries for each architecture. These files are stored for in e.g. `./target/x86_64-unknown-linux-gnu/release` for AMD64 (`x86_64`) release build. These files must be *un-excluded* from the `.dockerignore` file.
Add entries to `.dockerignore` for each [Architecture](#Architectures). The following pseudo-code must be added:
```bash=
for ARCH in "aarch64" "armv7" "x86_64"
do
NAME="${ARCH}-unknown-linux-gnu"
for TYPE in "debug" "release"
do
echo "!target/${NAME}/${TYPE}/${MEMBER_NAME}"
done
done
```
## GitHub Actions
The build process containerizes the cross-platform Rust binaries. It uses GitHub Actions to do this. Each Akri component has a GitHub Actions file.
+ Create `.github/workflows/build-${MEMBER_NAME}-container.yml`
+ Copy the content of one of the existing workflows
+ Search and replace content so that it matches `${MEMBER_NAME}`
Depending on the workflow's `on` trigger events, this Action may be triggered on subsequent pushes.
## Update `CHANGELOG.md`
## Versioning
Versioning is controlled by a state file (./version.txt) containing Akri's current SemVer and `./version.sh` which is the process that bumps and checks version increases.
You will need to revise `./version.sh` in 2 (!) places to ensure that `${MEMBER_PATH}/Cargo.toml` is bumped by `./version.sh`.
```bash
sed \
--in-place \
--regexp-extended \
"s|CARGO_FILES=\"(.*)\"|CARGO_FILES=\"\1 \$BASEDIR/${MEMBER_PATH}/Cargo.toml\"|g" \
./version.sh
```
Then:
+ `./version.sh -c -s`
+ `./version.sh -u -p`
## Makefile
You will need to add `${MEMBER_NAME}` to Akri's Makefile `./build/akri-containers.mk`.
> **NOTE** Makefiles reference variables as `$(NAME)`. In the following, to differentiate, you must replace values of the form `${NAME}` (braces) e.g. `${MEMBER_NAME}`
+ Update comments
+ `make akri-[controller|...|${MEMBER_NAME}]`
+ `BUILD_AMD64=1 BUILD_ARM32=0 BUILD_ARM64=1 make akri-[controller|...|${MEMBER_NAME}`
+ Append to `.PHONY` section `akri-${MEMBER_NAME}: akri-build akri-docker-${MEMBER_NAME}`
+ `akri-docker-build: ... ${MEMBER_NAME}-build`
+ Create 3 sections (see below) `${MEMBER_NAME}-build`
+ Append to `akri-docker-push-per-arch: ... ${MEMBER_NAME}-docker-per-arch`
+ Append to `akri-docker-push-multi-arch-push: ... ${MEMBER_NAME}-docker-multi-arch-push`
|MAKE|SHORT|LONG|
|----|-----|----|
|amd64|AMD64|AMD64|
|arm32|ARM32|ARM32V7|
|arm64|ARM64|ARM64V8|
```bash
NAME=${MEMBER_NAME}-build
${NAME}: ${NAME}-amd64 ${NAME}-arm32 ${NAME}-arm64
```
The following section content must be repeated for each of the architectures. However this section uses a mixture of `MAKE`, `SHORT` and `LONG` architecture names as defined above:
```Make
${NAME}-[[MAKE]]:
ifeq (1, ${BUILD_[[SHORT]]})
docker build $(CACHE_OPTION) --file=$(DOCKERFILE_DIR)/Dockerfile.${MEMBER_NAME} --tag=$(PREFIX)/${MEMBER_NAME}:$(LABEL_PREFIX)-$($[[LONG]]_SUFFIX) \
--build-arg PLATFORM=$(${[[LONG]]_SUFFIX) .
endif
```
And:
```Make
NAME=${MEMBER_NAME}-docker-per-arch
${NAME}: ${NAME}-amd64 ${NAME}-arm32 ${NAME}-arm64
```
The following section content must be repeated for each of the architectures:
```Make
${NAME}-[[MAKE]]:
ifeq (1, ${BUILD_[[SHORT]]})
docker push $(PREFIX)/${MEMBER_NAME}:$(LABEL_PREFIX)-$([[LONG]]_SUFFIX)
endif
```
And finally:
```Make
NAME=${MEMBER_NAME}-docker-multi-arch-create
${NAME}:
```
And, for each architecture:
```Make
ifeq (1, ${BUILD_[[SHORT]]})
$(ENABLE_DOCKER_MANIFEST) docker manifest create --amend $(PREFIX)/${MEMBER_NAME}:$(LABEL_PREFIX) $(PREFIX)/${MEMBER_NAME}:$(LABEL_PREFIX)-$([[LONG]]_SUFFIX)
endif
```
## Dockerfile
Create a file `./build/containers/Dockerfile.${MEMBER_NAME}`.
You may replicate the content from another Dockerfile but be careful to revise it to reflect your `${MEMBER_NAME}` details.
## Helm
You should revise Akri's Helm Chart (`./deployment/helm`) to incorporate `${MEMBER_NAME}`. You will probably need to add a section (called `${MEMBER_NAME}`) to `Values.yml`.
> **NOTE** Helm uses camelCase naming, revise your `${MEMBER_NAME}` to be camelCase when using it in Helm templates.
You may wish to replicate an existing section to ensure consistency.
Then create a template for your `${MEMBER_NAME}` in `./deployment/helm/templates/${MEMBER_NAME}.yaml` (**NB** `.yaml`). You may wish to use e.g. `agent.yaml` as a guide.