Emerald project architecture is based in containers and containers orchestration. In this section we will cover the basics of component development.
## Table of contents
-[Basics of component development](#basics-of-component-development)
-[Basics of component publishing](#basics-of-component-publishing)
-[Manual build and publish](#manual-build-and-publish)
-[Dockerfile](#dockerfile)
-[Build](#build)
-[Login](#login)
-[Publish](#publish)
## Basics of component publishing
Independent of the component nature: open source, or proprietary. It must have a repository in the Tecnalia GitLab. The repository must have a README.md and a LICENSE file.
In the case of open source components, the README.md will describe the usage of the component and the LICENSE file will contain the license of the component. By default, the license in Emerald project is Apache 2.0.
In the case of proprietary components, the README.md will describe the objective of the component and the means to access the component. The LICENSE file will contain the license of the component.
**Note: during the public release of the component, for proprietary components, only the README.md and the LICENSE file will be copied to the public repository.**
## Component placement in the Tecnalia GitLab
The components must be placed in the Tecnalia GitLab. The components must be placed in the `emerald/private/components` group. Inside we have prepared individual groups for each component, i.e `emerald/private/components/amoe`, `emerald/private/components/rcm`, etc.
**Note: if your component is not in the list, please contact the CaaS Framework administrator to create the group for your component.**
Inside, the component group, you can create repos for each of the images that your component require. For example, the `rcm` component has the following repositories: `frontend`, `backend` and `converter`.
Adittionally, if you require more repositories for your component, you can create them. For example, the `amoe` component has an internal group `emerald/private/components/amoe/python-clients` that contains the code generated with the client libraries. For example, `rcm` has a repository `docker-compose` that contains a compostion that we use to develop rcm, and it also has a `initial-data` component that contain the initial configuration data that we use in the docker-compose project.
## Manual build and publish
The manual build and publish is the simplest way to build and publish a component. It is useful for testing purposes.
To build and publish a component manually you will need a Dockerfile.
### Dockerfile
The Dockerfile is a text file that contains the instructions to build a docker image. The Dockerfile must be placed in the root of the component repository.
The following is an example of a Dockerfile:
```Dockerfile
FROM python:3.8-slim
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip install-r requirements.txt
COPY src src
CMD ["python", "src/main.py"]
```
The Dockerfile is a simple example of a python application. It installs the requirements, copies the source code and runs the main.py file.
### Build
To build the docker image, you can use the following command:
```bash
docker build -t my-component:latest .
```
This command will build the docker image with the tag `my-component:latest`.
### Login
To publish the docker image, you need to login to the docker image registry. You can use the following command:
When developing the dockerfile you should have in mind that depending of how you write the dockerfile, the docker image will be more or less efficient, stable and big. Here are some recommendations:
- Check the size of the resulting image. The size of the image is important because it affects the time it takes to download the image, the time it takes to start the container, and the amount of disk space that is used. You can use the `docker image ls` command to check the size of the image. If it is too big, you can try to reduce the size by removing unnecessary files, using a smaller base image, or using multi-stage builds.
- Avoid including large setup files inside the image. If you need to include large setup files, you can use a volume to mount the files at runtime. This will reduce the size of the image.
- Use versioned base images. For example, if you are developing a python application, you can use the `python:3.8-slim` image instead of the `python:latest` image. Using the `latest` tag can lead to unexpected behavior when the base image is updated.
- Use the smallest base image that you can. For example, if you are developing a python application, you can use the `python:3.8-slim` image instead of the `python:3.8` image.
- Install dependecies at the beginning of the Dockerfile. This will allow you to take advantage of the docker cache. If you change the source code, the dependencies will not be installed again. Saving lots of time. i.e.:
```Dockerfile
FROM python:3.8-slim
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip install-r requirements.txt
COPY src src
CMD ["python", "src/main.py"]
```
- Use multi-stage builds. If your application requires build stage with packages that are not needed in the final image, you can use multi-stage builds. i.e.:
```Dockerfile
FROMmaven:3.6.3-jdk-11ASbuild
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src src
RUN mvn package
FROM openjdk:11-jre-slim
WORKDIR /app
COPY --from=build /app/target/my-app.jar .
CMD ["java", "-jar", "my-app.jar"]
```
- Use COPY instead of ADD. The ADD instruction is more powerful than the COPY instruction. However, the ADD instruction can be confusing and lead to unexpected behavior. For example, the ADD instruction can download files from the internet. This can be a security risk.
- If you need to ensure permissions after COPY use `--chown` option. For example, if you copy a file and you need to ensure that the file has the correct permissions, you can use the `--chown` option. i.e.:
```Dockerfile
FROM python:3.8-slim
WORKDIR /app
COPY --chown=1000:1000 src src
CMD ["python", "src/main.py"]
```
- Combine instructions. If you can combine instructions, you can reduce the number of layers in the docker image. Do not forget to clean up the cache in the same instruction. Use Heredoc syntax to combine instructions. i.e.:
```Dockerfile
FROM python:3.8-slim
WORKDIR /app
RUN <<EOF
set -e
apt-get update
export DEBIAN_FRONTEND=noninteractive
apt-get install -y \
build-essential \
libpq-dev
apt-get clean
rm -rf /var/lib/apt/lists/*
EOF
COPY requirements.txt requirements.txt
RUN pip install-r requirements.txt
COPY src src
CMD ["python", "src/main.py"]
```
- Define the EXPOSE instruction. The EXPOSE instruction informs not only the user but also other utility containers (i.e. traefik) that the container listens on the specified network ports at runtime. i.e.:
```Dockerfile
FROM python:3.8-slim
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip install-r requirements.txt
COPY src src
EXPOSE 8080
CMD ["python", "src/main.py"]
```
- (Optional) Use the HEALTHCHECK instruction. The HEALTHCHECK instruction tells Docker how to test a container to check that it is still working. This can be used to detect when a container is unhealthy. i.e.:
- (Optional) Define VOLUME instruction. The VOLUME instruction creates a mount point with the specified name and marks it as holding externally mounted volumes from native host or other containers. i.e.: