# Other  improvements

- What about security of the code / packages?

- Choosing the proper build image might make a big difference:

- Look at the following two `Dockerfiles`:

```bash
FROM python:latest
RUN pip install redis
RUN pip install requests
COPY worker.py /
CMD ["python", "worker.py"]
```

```bash
FROM python:alpine
RUN pip install redis
RUN pip install requests
COPY worker.py /
CMD ["python", "worker.py"]
```

---

## The only difference is the base image.

- But the end result is quite different:

| Base image | Image size | CVE's |
|---|---|---|
| python:latest | 888 Mb | 1114 |
| python:alpine | 73,5 Mb | 3 |

  (Scanning is done with `grype` and since the writing of this presentation the numbers have increased)

---

## The 'full' python image has even `gcc` included....

```bash
docker run --rm --entrypoint gcc -it python-latest:latest
gcc: fatal error: no input files
compilation terminated.
```

```bash
docker run --rm --entrypoint gcc python-alpine:latest
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "gcc": executable file not found in $PATH: unknown.
```

---

## Consider a `multistage build`

```bash
FROM python:latest as builder
RUN pip install redis
RUN pip install requests
  # Do many other heavy things here
COPY worker.py /
CMD ["python", "worker.py"]


FROM python:alpine as runner
  # Copy file from previous build container
COPY --from=builder /worker.py .
RUN pip install redis
RUN pip install requests
  # Change UID here
USER 1234
CMD ["python", "worker.py"]
```

- The required code could be build in image 1 and transfered to image 2 leaving the majority of CVE's behind...

---

## Result multistage build

| Base image | Image size | CVE's |
|---|---|---|
| python:latest | 888 Mb | 1114 |
| python:alpine | 73,5 Mb | 3 |
| python:multistage | 73,5 Mb | 3 |
