diff --git a/src/assets/images/streamlitdocker.png b/src/assets/images/streamlitdocker.png new file mode 100644 index 0000000..77eee99 Binary files /dev/null and b/src/assets/images/streamlitdocker.png differ diff --git a/src/content/blog/Containerise-Streamlit-application-and-publish-image-to-ghcr.mdx b/src/content/blog/Containerise-Streamlit-application-and-publish-image-to-ghcr.mdx new file mode 100644 index 0000000..ccea2ef --- /dev/null +++ b/src/content/blog/Containerise-Streamlit-application-and-publish-image-to-ghcr.mdx @@ -0,0 +1,148 @@ +--- +heroImage: /src/assets/images/streamlitdocker.png +category: Containers +description: Containerise Streamlit application and publish image to ghcr +pubDate: 2024-06-09T22:00:00.000Z +draft: true +tags: + - docker + - containers + - streamlit +title: 'Streamlit Containerization: A Complete Guide with Docker Best Practices' +--- + +I needed to create a quick proof of concept (PoC) using Streamlit but had two constraints: + +- Self-host instead of using [Streamlit community cloud](https://streamlit.io/cloud) +- Control access to the deployed website + +With this in mind, containerizing and hosting on Azure was the solution. This post starts a series with the list of parts below: + +- Part 1: Containerized Streamlit app with a blank app.py file (just add your code). You are here😊 +- Part 2: GitHub workflow to build and publish the image to ghcr.io. +- Part 3: Terraform code to manage infrastructure on Azure. +- Part 4: GitHub workflow to execute Terraform apply & destroy infrastructure. + +# Prerequisite + +Prerequisite is Docker. Follow installation information + +# Docker best practices + +Here are the high-level best practices for building Docker images: + + • Use multi-stage builds to reduce image size and improve efficiency. + + • Choose the right base image from trusted sources and keep it small. + + • Rebuild images frequently to incorporate updates and patches. + + • Use .dockerignore to exclude unnecessary files. + + • Create ephemeral containers for stateless applications. + + • Avoid installing unnecessary packages to minimize the attack surface. + + • Decouple applications into separate containers. + + • Sort multi-line arguments for better readability. + + • Leverage build cache for faster builds. + + • Pin base image versions to ensure consistency. + + • Integrate image build and tests in CI/CD pipelines. + +For detailed information, visit [Docker Building Best Practices](https://docs.docker.com/build/building/best-practices/). + +[https://docs.docker.com/build/building/best-practices/](https://docs.docker.com/build/building/best-practices/) + +[https://codefresh.io/blog/docker-anti-patterns/](https://codefresh.io/blog/docker-anti-patterns/) + +# Create a docker file + +This is the full file we will create + +```dockerfile +FROM python:3.9-slim + +LABEL maintainer="Wayne Goosen" +LABEL version="1.0.0" +LABEL description="Streamlit template for Docker. Uses app.py as the main file." + +WORKDIR /app + +RUN apt-get update \ + && rm -rf /var/lib/apt/lists/* + +COPY requirements.txt . + +RUN pip3 install -r requirements.txt + +COPY .streamlit/config.toml .streamlit/ +COPY app.py . + +RUN groupadd -g 1005 appgroup && \ + useradd -u 1005 -g appgroup appuser && \ + chown -R appuser:appgroup /app + +EXPOSE 80 + +USER appuser + +ENTRYPOINT ["streamlit", "run"] +CMD ["app.py"] +``` + +# Dockerfile walkthrough + +- The base image is python:3.9-slim. +- The Dockerfile creates a working directory at /app. +- It updates the package lists for upgrades and new package installations. +- It copies requirements.txt into the Docker image and installs the Python dependencies. +- It copies app.py (the main application file) into the Docker image. +- It creates a group appgroup and a user appuser with group ID and user ID 1005, respectively. It then changes the ownership of the /app directory to appuser\:appgroup. +- It exposes port 8501 for the Streamlit application. +- It sets appuser as the user to run the subsequent commands and the application. +- The entrypoint is set to streamlit run, and the command is set to run app.py with server port 8501 and server address 0.0.0.0. + +# Build a docker image + +To build the Docker image, navigate to the directory containing the Dockerfile and run the following command: + +docker build -t my-streamlit-app . + +The -t flag is used to tag the image. Here, we have tagged the image streamlit. If you run: + +docker images + +You should see a streamlit image under the REPOSITORY column. For example: + +REPOSITORY TAG IMAGE ID CREATED SIZE +streamlit latest 70b0759a094d About a minute ago 1.02GB + +# Run the docker container + +To run the Docker container, use the following command: + +docker run -p 8501:80 my-streamlit-app\:latest + +To view your app, users can browse to [http://0.0.0.0:8501 or http://localhost:8501](http://0.0.0.0:8501 or http://localhost:8501)[ +](https://docs.docker.com/build/building/best-practices/) + +# Streamlit configuration + +Besides the config.toml (Describe this more detail) the configuration can be passed as a param: + +- "--server.port=8501" +- "--server.address=127.0.0.1" +- "--client.showErrorDetails=true" +- "--client.toolbarMode=minimal" + +Find more configuration [here](https://docs.streamlit.io/develop/api-reference/configuration/config.toml) + +Part 2 coming soon.. + +# References + +- [Deploy streamlit using Docker](https://docs.streamlit.io/deploy/tutorials/docker)