# OCI Env Deep Dive Pulpcon 2022 By David Newswanger --- ### Agenda 1. What is OCI Env 2. How does OCI Env Work? 3. OCI Env Profile system --- ### What is OCI Env? - A pulp developer environment to develop pulp using the pulp all in one images - Based off of the developer environment for galaxy_ng - Features: - Fast load times (sub 2 minutes to spin up) - Auto code reloading - Out of the box support for running tests - Helper functions for working on pulp - Podman and Docker support - Multi environment support --- ### Philosophy Ansible: Make the easy things easy and the hard things possible. - Everything must work out of the box with the least possible number of configurations and commands for developers to go from forking a pulp plugin and writing code. - The system must be flexible enough to allow for a wide variety of development modes. --- ### A quick demo of the basics - Setting up your environment - Tip: use `OCI_ENV_PATH` - Starting pulp - Running tests - Resetting the db - Accessing the shell --- ### Running multiple environments ```bash API_PORT=4002 COMPOSE_PROJECT_NAME=my_second_env SRC_DIR=~/code/tmp/pulpcon/src_path_2 COMPOSE_PROFILE= DEV_SOURCE_PATH=pulp_file COMPOSE_BINARY=docker ``` --- ### How does oci env work? - Builds a custom image off of the pulp all in one container that contains the utilities necessary to run the dev environment - Generates a set of docker/podman compose files for launching the environment - Uses the generated compose files to start and interact with the containers --- ### Containerfile `base/Dockerfile` ```Dockerfile FROM ghcr.io/pulp/pulp-ci-centos:latest # configure S6 to use env variables ENV S6_KEEP_ENV=1 COPY dev_requirements.txt /dev_requirements.txt RUN pip3 install -r dev_requirements.txt COPY settings.py /etc/pulp/settings.py COPY s6-rc.d/oci-env-prepare/ /etc/s6-overlay/s6-rc.d/oci-env-prepare/ COPY s6-rc.d/oci-env-profiles /etc/s6-overlay/s6-rc.d/oci-env-profiles/ RUN cd /etc/s6-overlay/s6-rc.d/user/contents.d && touch oci-env-prepare oci-env-profiles # Modify postgres so it starts after oci-env gets a chance to initialize the plugins from source COPY s6-rc-modifications/postgres-prepare/dependencies.d /etc/s6-overlay/s6-rc.d/postgres-prepare/dependencies.d # Modify pulpcore-api so it auto reloads COPY s6-rc-modifications/pulpcore-api/run /etc/s6-overlay/s6-rc.d/pulpcore-api/run COPY utils.sh /utils.sh ``` --- ### Base compose file ```yaml --- version: "3.7" services: _base: build: context: "{OCI_ENV_DIR}/base/" dockerfile: "Dockerfile" image: "localhost/oci_env/pulp:base" entrypoint: "/bin/true" pulp: image: "localhost/oci_env/pulp:base" cap_add: - SYS_PTRACE env_file: - "{OCI_ENV_DIR}/.compiled/{COMPOSE_PROJECT_NAME}/combined.env" - "{OCI_ENV_CONFIG_FILE}" environment: - "DEV_SOURCE_PATH={DEV_SOURCE_PATH}" - "DJANGO_SUPERUSER_USERNAME={DJANGO_SUPERUSER_USERNAME}" - "DJANGO_SUPERUSER_PASSWORD={DJANGO_SUPERUSER_PASSWORD}" - "API_HOST={API_HOST}" - "API_PORT={API_PORT}" - "API_PROTOCOL={API_PROTOCOL}" - "NGINX_PORT={NGINX_PORT}" - "NGINX_SSL_PORT={NGINX_SSL_PORT}" - "COMPOSE_PROJECT_NAME={COMPOSE_PROJECT_NAME}" - S6_BEHAVIOUR_IF_STAGE2_FAILS=0 ports: - "{API_PORT}:{NGINX_PORT}" depends_on: - _base volumes: - "{SRC_DIR}:/src:z" - "{OCI_ENV_DIR}:/opt/oci_env:z" - "oci_pulp:/var/lib/pulp" - "oci_redis_data:/data" - "oci_pg_data:/var/lib/pgsql" volumes: oci_pulp: name: "{COMPOSE_PROJECT_NAME}_pulp" oci_pg_data: name: "{COMPOSE_PROJECT_NAME}_pg_data" oci_redis_data: name: "{COMPOSE_PROJECT_NAME}_redis_data" ``` --- ### Compose file generation 1. Load the environment configuration from your compose.env file 2. Parse the profiles defined in the env file 3. Compile the profiles to be used by the container runtime - Perform variable substitution - Parse pulp settings from profiles - Create init.sh script --- ### Container Launch ```shell # Inspect the container command with -v $ oci-env -v compose up Running command in container: docker-compose -p oci_env -f /Users/dnewswan/code/tmp/pulpcon/oci_env/.compiled/oci_env/base_compose.yaml up Starting oci_env__base_1 ... done Starting oci_env_pulp_1 ... done $ oci-env -v shell Running command in container: docker exec -it oci_env_pulp_1 bash ``` --- ### oci-env CLI - Executes podman/docker compose commands ```shell oci-env compose <args> # Is a wrapper on top of podman-comopose <args> ``` --- ### oci-env CLI - Executes commands inside the container - Can be a script in the container found in base/container_scripts/. - Can be a direct command. ```shell # Run the base/container_scripts/database_reset.sh script in the container oci-env -v db reset Running command in container: docker exec -it oci_env_pulp_1 bash /opt/oci_env/base/container_scripts/database_reset.sh # Runs podman exec -it bash oci-env -v shell Running command in container: docker exec -it oci_env_pulp_1 bash ``` --- ### oci-env CLI - Executes commands on the host machine - Currently just the `base/local_scripts/generate_client.sh` for the `oci-env generate-client` command ```shell # runs base/local_scripts/generate_client.sh oci-env -v generate-client Running local command: bash /Users/dnewswan/code/tmp/pulpcon/oci_env/base/local_scripts/generate_client.sh pulpcore ``` --- ## Profiles --- ### What are profiles? - A system to easily configure the developer environment to operate in different deployment modes. - Goes beyond just changing settings.py - Can define extra services to run alongside pulp - S3 Storage - Keycloak authentication - Web UI - Can define specific configurations for pulp - Can run arbitrary bash scripts to set up objects in the database or install extra dependencies. --- ### Let's write a new profile! Goal: launch a fileserver alongside pulp file that we can use to test pulp file syncs with. --- ### Create the profile ```shell $ oci-env profile init -p pulp_file fs New profile "pulp_file/fs" successfully created at: /Users/dnewswan/code/tmp/pulpcon/pulp_file/profiles/fs To use it set "COMPOSE_PROFILE=pulp_file/fs" $ tree ../pulp_file/profiles ../pulp_file/profiles └── fs ├── README.md ├── compose.yaml ├── init.sh ├── profile_requirements.txt └── pulp_config.env ``` --- - README.md: documentation for using the profile. - compose.yaml: compose file to define any new services that the profile provides. - init.sh: shell script that runs when the container starts for the first time to initialize any extra stuff the profile needs - profile_requirements.txt: a list of other profiles that this profile may need to function - pulp_config.env: a set of environment variables that the profile requires to run --- ### Our compose.yaml ```yaml --- version: "3.7" services: fileserver: build: context: "{SRC_DIR}/pulp_file/profiles/fs/" dockerfile: "containerfile" ports: - "8001:80" volumes: - "{WEBSERVER_DIR}:/usr/local/apache2/htdocs/" ``` --- ### containerfile for our service containerfile ```Dockerfile FROM registry.hub.docker.com/library/httpd:alpine # INSTALL PYTHON IN THE HTTPD IMAGE ENV PYTHONUNBUFFERED=1 RUN apk add --update --no-cache python3 git && ln -sf python3 /usr/bin/python RUN python3 -m ensurepip RUN pip3 install --no-cache --upgrade pip setuptools # INSTALL PULP MANIFEST RUN pip install git+https://github.com/pulp/pulp-manifest.git COPY cmd.sh /cmd.sh RUN chmod u+x /cmd.sh CMD /cmd.sh ``` --- ### cmd.sh to launch our service cmd.sh ```bash # /bin/bash pulp-manifest /usr/local/apache2/htdocs/ httpd-foreground ``` --- ### Our init.sh file ```bash #!/bin/bash sleep 10 pulp file remote create --name my_test_remote --url http://fileserver:80/PULP_MANIFEST pulp file repository create --name demo_repo --remote my_test_remote ``` --- ### Our pulp_config.env ``` PULP_ALLOWED_CONTENT_CHECKSUMS=['sha1', 'sha224', 'sha256', 'sha384', 'sha512'] ``` --- ### Configuring our environment ``` COMPOSE_PROFILE=pulp_file/fs DEV_SOURCE_PATH=pulpcore:pulp_file COMPOSE_BINARY=docker WEBSERVER_DIR=~/code/tmp/pulpcon/webserver ``` --- ### Shipping profiles with plugins - Profiles can (and should!) be shipped with plugins - oci-env can load any profile from the `<plugin>/profiles/` directory ```shell $ oci-env profile ls Plugin: oci_env galaxy_base pulp_rpm_base pulp_ansible_base galaxy_ui Plugin: pulp_file pulp_file/fs ``` --- ### Multiple profiles - Multiple profiles can be specified with the `:` separator - Example: configure pulp file to run with an s3 backend and our new fileserver profile ``` COMPOSE_PROFILE=s3:pulp_file/fs DEV_SOURCE_PATH=pulpcore:pulp_file ``` --- ### Multiple compose files `docker-compose` and `podman-compose` both allow for the `-f` flag that allows a user to specify as many compose files as you want. ```shell docker-compose -f compose1.yaml -f compose2.yaml -f compose3.yaml ``` This allows for multiple compose yaml files to be combined into one. oci-env leverages this to combine all of the compose.yaml files in each profile into one compose file. --- ### Compose file tricks - Any compose file can modify any compose file that comes before it. ```yaml --- version: "3.7" services: pulp: image: "my_custom_image:latest" ``` --- # Q and A ---