Creating Execution Environments and Deploying Content
Problem
You want to create a custom environment for your content, and then deploy content using it.
Solution
You must have administrator privileges to create environments.
Creating a custom environment
First, we define an image that will be used to execute our content on Connect. We use the Posit Connect content image as the base and install the additional Python and R packages that our content requires.
FROM ghcr.io/posit-dev/connect-content:R4.3.3-python3.11.15-ubuntu-24.04
ARG GIT_SHA="b7ce8e7bb0ae4cf3b5fd809ad67c89b26d2a5f36"
ARG CRAN_MIRROR="https://p3m.dev/cran/__linux__/noble/latest"
ARG PYPI_MIRROR="https://p3m.dev/pypi/latest/simple"
# Install the Python packages.
# This installs the Python packages defined in requirements.txt, which pins
# the package versions and provides an immutable set of Python dependencies.
RUN pip install --upgrade pip && \
curl -sSfL https://raw.githubusercontent.com/posit-dev/connect-extensions/${GIT_SHA}/extensions/pqr/requirements.txt \
-o /tmp/requirements.txt && \
pip install --default-timeout=1000 --index-url=${PYPI_MIRROR} -r /tmp/requirements.txt && \
rm /tmp/requirements.txt
# Install the R packages from the example's renv lockfile.
ENV RENV_PATHS_LIBRARY=renv/library
RUN R -e $"install.packages('renv', repos = c(CRAN = '${CRAN_MIRROR}'))" && \
curl -sSfL https://raw.githubusercontent.com/posit-dev/connect-extensions/${GIT_SHA}/extensions/pqr/renv.lock \
-o /tmp/renv.lock && \
R -e $"renv::restore(lockfile='/tmp/renv.lock', repos = c(CRAN = '${CRAN_MIRROR}'))" && \
rm /tmp/renv.lockThen, build and push the image to your organization’s container registry.
Terminal
# use a container registry that you have push access to
CONTAINER_REGISTRY="myorg/myrepo"
docker build . -t ${CONTAINER_REGISTRY}/pqr:R4.3.3-python3.11.15
docker push ${CONTAINER_REGISTRY}/pqr:R4.3.3-python3.11.15Next, we use the Environments API to create an execution environment.
The value for matching in the environment created is exact. This indicates that the environment should only be used if it is explicitly requested by a piece of content. Connect never chooses this environment during automatic selection.
from posit import connect
CONTAINER_REGISTRY = "myorg/myrepo"
client = connect.Client()
client.environments.create(
title= "Custom pqr",
description= "Custom environment for the pqr example content",
cluster_name= "Kubernetes",
name= f"{CONTAINER_REGISTRY}/pqr:R4.3.3-python3.11.15",
matching= "exact",
r={
"installations": [
{"version": "4.3.3", "path": "/opt/R/4.3.3/bin/R"}
]
},
python={
"installations": [
{"version": "3.11.15", "path": "/opt/python/3.11.15/bin/python3"}
]
},
quarto={
"installations": [
{"version": "1.9.37", "path": "/opt/quarto/1.9.37/bin/quarto"}
]
},
)library(connectapi)
CONTAINER_REGISTRY = "myorg/myrepo"
client = connect()
json_payload <- toJSON(list(
title = "Custom pqr",
description = "Custom environment for the pqr example content",
cluster_name = "Kubernetes",
name = paste0(CONTAINER_REGISTRY, "/pqr:R4.3.3-python3.11.15"),
matching = "exact",
r = list(
installations = list(
list(version = "4.3.3", path = "/opt/R/4.3.3/bin/R")
)
),
python = list(
installations = list(
list(version = "3.11.15", path = "/opt/python/3.11.15/bin/python3")
)
),
quarto = list(
installations = list(
list(version = "1.9.37", path = "/opt/quarto/1.9.37/bin/quarto")
)
)
), auto_unbox = TRUE, pretty = TRUE)
client$POST("/v1/environments", json_payload)Deploying content
Now that we have created our custom environment, we can deploy content using it.
First, create a new content item using the Connect Server API.
In the command below, the request payload specifies initial values for default_image_name, default_r_environment_management, and default_py_environment_management:
- By setting
default_image_nameduring the initial deployment, we ensure that Connect uses our custom image the first time the content builds during the deployment. - We specify
falsefor bothdefault_r_environment_managementanddefault_py_environment_managementso that Connect does not attempt to install any R or Python packages during the first build. Then, when the content executes, it uses the packages that are installed on the image, rather than packages from the cache.
Terminal
curl -XPOST -H "Authorization: key ${CONNECT_API_KEY}" ${CONNECT_SERVER}/__api__/v1/content \
--data '{
"name": "my-pqr-app",
"default_image_name": "'${CONTAINER_REGISTRY}'/pqr:R4.3.3-python3.11.15",
"default_r_environment_management": false,
"default_py_environment_management": false
}'Make a note of the guid in the server response. We use this as our CONTENT_GUID later when we deploy our application.
Next, clone the content to the workstation and create a content bundle so that we can publish it to the Connect server.
Terminal
# clone the repo
git clone https://github.com/posit-dev/connect-extensions.git
cd connect-extensions
git checkout b7ce8e7bb0ae4cf3b5fd809ad67c89b26d2a5f36
# create the content bundle from the pqr example directory
tar czvf bundle.tar.gz -C ./extensions/pqr ./
# upload the content bundle to Posit Connect
curl -XPOST -H "Authorization: key ${CONNECT_API_KEY}" ${CONNECT_SERVER}/__api__/v1/content/${CONTENT_GUID}/bundles \
--data-binary @"bundle.tar.gz"Make a note of the id in the server response. We use this as our BUNDLE_ID in the next step.
Now, activate the bundle to complete the content deployment.
Terminal
curl -XPOST -H "Authorization: key ${CONNECT_API_KEY}" ${CONNECT_SERVER}/__api__/v1/content/${CONTENT_GUID}/deploy \
--data '{
"bundle_id": "'${BUNDLE_ID}'"
}'The deploy log for the job (visible under Logs in the Connect UI) confirms that Connect matched the bundle to our custom environment and skipped package installation, since the image already contains them:
Bundle created with R version 4.3.2 (>=4.3), Python version 3.11.13 (>=3.11), and Quarto version 1.7.34 (>=1.4) is compatible with environment Kubernetes::myorg/myrepo/pqr:R4.3.3-python3.11.15 with R version 4.3.3 from /opt/R/4.3.3/bin/R, Python version 3.11.15 from /opt/python/3.11.15/bin/python3, and Quarto version 1.9.37 from /opt/quarto/1.9.37/bin/quarto
Bundle requested no R environment restore; Connect will not perform any R package installation.
Bundle requested no Python environment restore; Connect will not perform any Python package installation.
Bundle requested Quarto version 1.7.34 (>=1.4); using /opt/quarto/1.9.37/bin/quarto which has version 1.9.37
Launching Quarto document...
Using environment Kubernetes::myorg/myrepo/pqr:R4.3.3-python3.11.15
Using /opt/quarto/1.9.37/bin/quarto with version 1.9.37 from Kubernetes::myorg/myrepo/pqr:R4.3.3-python3.11.15
Using /opt/R/4.3.3/bin/R with version 4.3.3 from Kubernetes::myorg/myrepo/pqr:R4.3.3-python3.11.15
Using /opt/python/3.11.15/bin/python3 with version 3.11.15 from Kubernetes::myorg/myrepo/pqr:R4.3.3-python3.11.15The deployed content should now be fully published and available on the Connect UI.