diff --git a/src/jetbrain-space/docker-compose.yml b/src/jetbrain-space/docker-compose.yml new file mode 100644 index 0000000..f0bd2d3 --- /dev/null +++ b/src/jetbrain-space/docker-compose.yml @@ -0,0 +1,164 @@ +version: '3.8' + +services: + init-configs: + image: "public.registry.jetbrains.space/p/space-on-premises/docker/init-configs:2023.3.1" + volumes: + - config:/home/init-config/config + environment: + AUTOMATION_TAG: "2023.3.1.87" + SPACE_VERSION: "2023.3.1" + space: + image: "public.registry.jetbrains.space/p/space-on-premises/docker/space:2023.3.1" + volumes: + - config:/home/space/circlet-server-onprem/config + environment: + JAVA_OPTS: "-Dconfig.file=/home/space/circlet-server-onprem/config/space.on-premises.conf -Dconfig.override_with_env_vars=true" + depends_on: + init-configs: + condition: service_completed_successfully + vcs: + condition: service_started + redis: + condition: service_started + postgres: + condition: service_started + minio: + condition: service_started + elasticsearch: + condition: service_healthy + ports: + - "8084:8084" + networks: + - "frontend" + - "backend-apps" + - "backend-data" + + vcs: + image: "public.registry.jetbrains.space/p/space-on-premises/docker/vcs-hosting:2023.3.1" + volumes: + - config:/home/space/git/vcs-hosting/config + environment: + JAVA_OPTS: '-Dproperties.file=config/vcs.on-premises.properties' + depends_on: + init-configs: + condition: service_completed_successfully + redis: + condition: service_started + postgres: + condition: service_started + minio: + condition: service_started + elasticsearch: + condition: service_healthy + ports: + - "2222:2222" + - "8080:8080" + networks: + - "frontend" + - "backend-apps" + - "backend-data" + + packages: + image: "public.registry.jetbrains.space/p/space-on-premises/docker/packages:2023.3.1" + volumes: + - config:/home/space/packages-server/config + environment: + JAVA_OPTS: '-Dconfig.file=/home/space/packages-server/config/packages.on-premises.conf -Dconfig.override_with_env_vars=true' + depends_on: + init-configs: + condition: service_completed_successfully + redis: + condition: service_started + postgres: + condition: service_started + minio: + condition: service_started + elasticsearch: + condition: service_healthy + ports: + - "8390:8390" + - "9390:9390" + networks: + - "frontend" + - "backend-apps" + - "backend-data" + + langservice: + image: "public.registry.jetbrains.space/p/space-on-premises/docker/langservice:2023.3.1" + volumes: + - config:/home/space/langservice-server/config + environment: + JAVA_OPTS: "-Dconfig.file=/home/space/langservice-server/config/langservice.on-premises.conf -Dconfig.override_with_env_vars=true" + depends_on: + init-configs: + condition: service_completed_successfully + ports: + - "8095" + networks: + - "backend-apps" + + postgres: + image: "postgres:12.2" + volumes: + - db_data:/var/lib/postgresql/data + environment: + POSTGRES_USER: space + POSTGRES_PASSWORD: spacepassword + POSTGRES_DB: spacedb + ports: + - "5432" + networks: + - "backend-data" + + elasticsearch: + image: "elasticsearch:7.17.7" + volumes: + - elasticsearch_data:/usr/share/elasticsearch/data + environment: + ES_JAVA_OPTS: -Xms512m -Xmx1024m + discovery.type: single-node + xpack.security.enabled: "false" + ports: + - "9200" + - "9300" + healthcheck: + test: [ "CMD", "curl", "-f", "http://localhost:9200/_cat/health" ] + interval: 5s + timeout: 5s + retries: 10 + start_period: 20s + networks: + - "backend-data" + + redis: + image: "redis:7.0.2-alpine" + ports: + - "6379" + networks: + - "backend-data" + + minio: + image: minio/minio:RELEASE.2021-09-09T21-37-07Z + volumes: + - minio_data:/data + environment: + MINIO_ROOT_USER: space-access-key + MINIO_ROOT_PASSWORD: space-secret-key + command: server --address :9000 --console-address :9001 --compat /data + ports: + - "9000:9000" + - "9001" + networks: + - "backend-data" +volumes: + elasticsearch_data: {} + db_data: {} + minio_data: {} + config: {} + +networks: + frontend: {} + backend-apps: {} + backend-data: {} + diff --git a/src/prefect-docker-compose-main/README.md b/src/prefect-docker-compose-main/README.md new file mode 100644 index 0000000..58507f5 --- /dev/null +++ b/src/prefect-docker-compose-main/README.md @@ -0,0 +1,195 @@ +# Prefect - Docker Compose + +A simple guide to understand and make Prefect **2.x** work with your own docker-compose configuration. + +Interested in examples for Prefect **1.x** ? Switch to the [last 1.x branch of this repo](https://github.com/flavienbwk/prefect-docker-compose/tree/e758a498d5819550a9b926b0bf9bb4e9c85574d1). + +This allows you to package your Prefect instance for fully-containerized environments (e.g: docker-compose, Kubernetes) or offline use. + +![Operating principle of Prefect](./prefect_schema_principle.jpg) + +- [Prefect - Docker Compose](#prefect---docker-compose) + - [Run the server](#run-the-server) + - [Run one or multiple agents](#run-one-or-multiple-agents) + - [Run your first flow via the Prefect API](#run-your-first-flow-via-the-prefect-api) + - [Principles to understand](#principles-to-understand) + - [Flow with Local storage (easiest)](#flow-with-local-storage-easiest) + - [Flow with S3 Storage (recommended)](#flow-with-s3-storage-recommended) + - [Flow with Docker storage](#flow-with-docker-storage) + - [Preparing the Registry](#preparing-the-registry) + - [Start the Docker in Docker agent](#start-the-docker-in-docker-agent) + - [Registering the flow](#registering-the-flow) + +## Run the server + +1. Optionally open and edit the [`server/.env`](./server/.env) file + + :information_source: All `PREFECT_*` env variables can be [found in the Prefect settings.py file](https://github.com/PrefectHQ/prefect/blob/main/src/prefect/settings.py#L238). + +2. Start the server : + + ```bash + cd server && docker-compose up --build -d && cd - + ``` + +3. Access the Orion UI at [localhost:4200](http://localhost:4200) + +## Run one or multiple agents + +Agents are services that run your scheduled flows. + +1. Optionally open and edit the [`agent/docker-compose.yml`](./agent/docker-compose.yml) file. + + > :information_source: In each `docker-compose.yml`, you will find the `PREFECT_API_URL` env variable including the `172.17.0.1` IP address. This is the IP of the Docker daemon on which are exposed all exposed ports of your containers. This allows containers launched from different docker-compose networks to communicate. Change it if yours is different (check your daemon IP by typing `ip a | grep docker0`). + > + > ![Docker interface IP](./docker_interface.png) + > + > Here, mine is `192.168.254.1` but the default is generally to `172.17.0.1`. + +2. Start the agent : + + ```bash + docker-compose -f agent/docker-compose.yml up -d + ``` + + > :information_source: You can run the agent on another machine than the one with the Prefect server. Edit the `PREFECT_API_URL` env variable for that. + + Maybe you want to instanciate multiple agents ? + + ```bash + docker-compose -f agent/docker-compose.yml up -d --scale agent=3 agent + ``` + +3. Our agents are now starting listening the Orion server on the `flows-example-queue` queue ([see the `--work-queue` option](./agent/docker-compose.yml#L7)). + +## Run your first flow via the Prefect API + +### Principles to understand + +> :speech_balloon: [Execution in your cloud; orchestration in ours](https://medium.com/the-prefect-blog/the-prefect-hybrid-model-1b70c7fd296) + +This means the Prefect server never stores your code. It just orchestrates the running (optionally the scheduling) of it. + +1. After developing your flow, Prefect will register it to the Orion server [through a Deployment](./client/app/weather.py#L49). In that script, you may ask the server to run your flow 3 times a day, for example. +2. Your code never lies on the Prefect server : this means the code has to be stored somewhere accessible to the agents in order to be executed. + + Prefect has [a lot of storage options](https://docs.prefect.io/tutorials/storage) but the most famous are : Local, S3, Docker and git. + - Local : saves the flows to be run on disk. So the volume where you save the flows must be [shared among your client and your agent(s)](./client/docker-compose.yml#L9). Requires your agent to have the same environment than your client (Python modules, packages installed etc... (the same Dockerfile if your agent and client are containers)) + - S3 : similar to local, but saves the flows to be run in S3 objects. + - Docker : saves the flows to be run as Docker images to your Docker Registry so your agents can easily run the code. + +### Flow with Local storage (easiest) + +:information_source: If your agents are installed among multiple machines, I recommend you to mount a shared directory with SSHFS. + +1. Run the following command to register your deployment and run the flow : + + ```bash + docker-compose -f client/docker-compose.yml up # Executes weather.py + ``` + +2. Access the UI to see your flow correctly run + +### Flow with S3 Storage (recommended) + +
+Tutorial for S3 Storage +
+ +We will use [MinIO](https://www.github.com/minio/minio) as our S3 server. + +1. Optionally open and edit the [`client_s3/.env`](./client_s3/.env) file and start MinIO + + ```bash + docker-compose -f client_s3/docker-compose.yml up -d minio # Starts MinIO + ``` + +2. Register the flow : + + ```bash + docker-compose -f client_s3/docker-compose.yml up weather # Executes weather.py + ``` + +Now your flow is registered. You can access the UI to run it. + +
+ +### Flow with Docker storage + +This method requires our client AND agent containers to have access to Docker so they can package or load the image in which the flow will be executed. We use _Docker in Docker_ for that. + +
+Tutorial for (secure) Docker Storage + +#### Preparing the Registry + +A Docker Registry is needed in order to save images that are going to be used by our agents. + +1. Generate the authentication credentials for our registry + + ```bash + sudo apt install apache2-utils # required to generate basic_auth credentials + cd client_docker/registry/auth && htpasswd -B -c .htpasswd myusername && cd - + ``` + + > To add more users, re-run the previous command **without** the -c option + +2. Start the registry + + ```bash + docker-compose -f client_docker/docker-compose.yml up -d registry + ``` + +3. Login to the registry + + You need to allow your Docker daemon to push to this registry. Insert this in your `/etc/docker/daemon.json` (create if needed) : + + ```json + { + "insecure-registries": ["172.17.0.1:5000"] + } + ``` + +4. Start the registry + + ```bash + docker login http://172.17.0.1:5000 # with myusername and the password you typed + ``` + + You should see : _Login Succeeded_ + +#### Start the Docker in Docker agent + +Optionally edit registry credentials in [`./agent_docker/docker-compose.yml`](./agent_docker/docker-compose.yml) and run : + +```bash +docker-compose -f agent_docker/docker-compose.yml up --build -d +``` + +#### Registering the flow + +We're going to push our Docker image with Python dependencies and register our flow. + +1. Build, tag and push the image + + ```bash + docker build . -f ./client_docker/execution.Dockerfile -t 172.17.0.1:5000/weather/base_image:latest + ``` + + > You **must** prefix your image with the registry URI `172.17.0.1:5000` to push it + + ```bash + docker push 172.17.0.1:5000/weather/base_image:latest + ``` + +2. Register the flow + + Optionally edit registry credentials in `./client_docker/docker-compose.yml` and run : + + ```bash + docker-compose -f ./client_docker/docker-compose.yml up --build weather + ``` + +Now your flow is registered. You can access the UI to run it. + +
diff --git a/src/prefect-docker-compose-main/agent/Dockerfile b/src/prefect-docker-compose-main/agent/Dockerfile new file mode 100644 index 0000000..5cbbfd0 --- /dev/null +++ b/src/prefect-docker-compose-main/agent/Dockerfile @@ -0,0 +1,4 @@ +FROM python:3.10 + +RUN apt update && apt install uuid -y +RUN pip install prefect==2.4.2 psycopg2-binary==2.9.3 s3fs==2022.8.2 minio==7.1.11 diff --git a/src/prefect-docker-compose-main/agent/docker-compose.yml b/src/prefect-docker-compose-main/agent/docker-compose.yml new file mode 100644 index 0000000..b4e5155 --- /dev/null +++ b/src/prefect-docker-compose-main/agent/docker-compose.yml @@ -0,0 +1,12 @@ +version: "3.7" + +services: + + agent: + build: . + command: bash -c "prefect agent start --work-queue flows-example-queue" + environment: + PREFECT_API_URL: "http://172.17.0.1:4200/api" + volumes: + - /srv/docker/prefect/flows:/root/.prefect/flows + - /srv/docker/prefect/flows:/flows diff --git a/src/prefect-docker-compose-main/agent_docker/Dockerfile b/src/prefect-docker-compose-main/agent_docker/Dockerfile new file mode 100644 index 0000000..8cc2dce --- /dev/null +++ b/src/prefect-docker-compose-main/agent_docker/Dockerfile @@ -0,0 +1,7 @@ +FROM docker:20.10-dind-rootless +ENV TZ="Europe/Paris" + +USER root +RUN apk update && apk add build-base libffi-dev python3 python3-dev py3-pip gcc linux-headers musl-dev util-linux + +RUN pip3 install --upgrade pip && pip3 install prefect==2.4.2 diff --git a/src/prefect-docker-compose-main/agent_docker/docker-compose.yml b/src/prefect-docker-compose-main/agent_docker/docker-compose.yml new file mode 100644 index 0000000..5f373bb --- /dev/null +++ b/src/prefect-docker-compose-main/agent_docker/docker-compose.yml @@ -0,0 +1,20 @@ +version: "3.7" + +services: + + agent: + build: . + privileged: true # forced for Docker DinD + entrypoint: ["/bin/sh", "-c"] + command: + - | + docker login -u=myusername -p=test http://172.17.0.1:5000 + mkdir -p /opt/prefect/flows + prefect agent start --work-queue flows-example-queue-docker + environment: + PREFECT_API_URL: "http://172.17.0.1:4200/api" + volumes: + - type: bind + source: /var/run/docker.sock + target: /var/run/docker.sock + read_only: true diff --git a/src/prefect-docker-compose-main/client/Dockerfile b/src/prefect-docker-compose-main/client/Dockerfile new file mode 100644 index 0000000..c450a42 --- /dev/null +++ b/src/prefect-docker-compose-main/client/Dockerfile @@ -0,0 +1,6 @@ +FROM python:3.10 + +RUN apt update && apt install uuid -y +RUN pip install prefect==2.4.2 + +WORKDIR /usr/app diff --git a/src/prefect-docker-compose-main/client/app/weather.py b/src/prefect-docker-compose-main/client/app/weather.py new file mode 100644 index 0000000..88200b4 --- /dev/null +++ b/src/prefect-docker-compose-main/client/app/weather.py @@ -0,0 +1,59 @@ +# A simple example to demonstrate Prefect is working as expected +# Works with a local folder shared with the agents (/root/.prefect/flows by default). + +import json + +import requests +from prefect import flow, task, get_run_logger +from prefect.deployments import Deployment +from prefect.filesystems import LocalFileSystem + +# --- Flow definition + +@task +def get_city_coordinates(city: str): + logger = get_run_logger() + cities = { + "Paris": (2.3510, 48.8567) + } + logger.info("Getting {}'s coordinates".format(city)) + return cities[city] + + +@task +def get_weather(longitude: float, latitude: float): + logger = get_run_logger() + logger.info(f"Getting weather of latitude={latitude} and longitude={longitude}") + api_endpoint = f"https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}&hourly=temperature_2m" + response = requests.get(api_endpoint) + if response.status_code == 200: + weather_data = json.loads(response.text) + logger.debug(weather_data) + return weather_data + else: + raise Exception("Failed to query " + api_endpoint) + + +@flow(name="get_paris_weather") +def get_paris_weather(): + city_coordinates = get_city_coordinates("Paris") + return get_weather(city_coordinates[0], city_coordinates[1]) + +# --- Deployment definition + +if __name__ == '__main__': + + block_storage = LocalFileSystem(basepath="/flows") + block_storage.save("local-storage", overwrite=True) + + deployment = Deployment.build_from_flow( + name="get_weather_local_example", + flow=get_paris_weather, + storage=LocalFileSystem.load("local-storage"), + work_queue_name="flows-example-queue" + ) + deployment.apply() + + # --- Execute the flow + + get_paris_weather() diff --git a/src/prefect-docker-compose-main/client/docker-compose.yml b/src/prefect-docker-compose-main/client/docker-compose.yml new file mode 100644 index 0000000..144b6c2 --- /dev/null +++ b/src/prefect-docker-compose-main/client/docker-compose.yml @@ -0,0 +1,12 @@ +version: "3.7" + +services: + + weather: + build: . + command: python3 /usr/app/weather.py + volumes: + - /srv/docker/prefect/flows:/flows + - ./app:/usr/app:ro + environment: + PREFECT_API_URL: "http://172.17.0.1:4200/api" diff --git a/src/prefect-docker-compose-main/client_docker/Dockerfile b/src/prefect-docker-compose-main/client_docker/Dockerfile new file mode 100644 index 0000000..b436b03 --- /dev/null +++ b/src/prefect-docker-compose-main/client_docker/Dockerfile @@ -0,0 +1,10 @@ +FROM docker:20.10-dind-rootless +ENV TZ="Europe/Paris" + +USER root +RUN apk update && apk add build-base libffi-dev python3 python3-dev py3-pip gcc linux-headers musl-dev util-linux + +RUN pip3 install --upgrade pip && pip3 install prefect==2.4.2 docker==6.0.0 + +COPY ./entrypoint.sh /entrypoint.sh +ENTRYPOINT [ "sh", "/entrypoint.sh" ] diff --git a/src/prefect-docker-compose-main/client_docker/app/weather.py b/src/prefect-docker-compose-main/client_docker/app/weather.py new file mode 100644 index 0000000..4f5ca72 --- /dev/null +++ b/src/prefect-docker-compose-main/client_docker/app/weather.py @@ -0,0 +1,111 @@ +# A simple example to demonstrate Prefect is working as expected +# Works with a local folder shared with the agents (/root/.prefect/flows by default). + +import json +import os +import shutil +import tarfile +import tempfile +import uuid +from datetime import datetime + +import requests +from prefect import flow, get_run_logger, task +from prefect.deployments import Deployment +from prefect.infrastructure.docker import DockerContainer, DockerRegistry + +# --- Flow definition + + +@task +def get_city_coordinates(city: str): + logger = get_run_logger() + cities = {"Paris": (2.3510, 48.8567)} + logger.info("Getting {}'s coordinates".format(city)) + return cities[city] + + +@task +def get_weather(longitude: float, latitude: float): + logger = get_run_logger() + logger.info(f"Getting weather of latitude={latitude} and longitude={longitude}") + api_endpoint = f"https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}&hourly=temperature_2m" + response = requests.get(api_endpoint) + if response.status_code == 200: + weather_data = json.loads(response.text) + logger.debug(weather_data) + return weather_data + else: + raise Exception("Failed to query " + api_endpoint) + + +@flow(name="get_paris_weather_docker") +def get_paris_weather(): + city_coordinates = get_city_coordinates("Paris") + weather_content = get_weather(city_coordinates[0], city_coordinates[1]) + logger = get_run_logger() + logger.info(weather_content) + return True + + +# --- Deployment definition + +if __name__ == "__main__": + from io import BytesIO + from docker import APIClient + + flow_identifier = datetime.today().strftime("%Y%m%d%H%M%S-") + str(uuid.uuid4()) + + # Mimicking Prefect 1.x image build for Prefect 2.x + + ## 1. Creating Docker build context (including flow files) + base_image = f"{os.environ.get('REGISTRY_ENDPOINT')}/weather/base_image:latest" + flow_image = ( + f"{os.environ.get('REGISTRY_ENDPOINT')}/weather/flow_image:{flow_identifier}" + ) + dockerfile = f""" + FROM {base_image} + RUN mkdir -p /usr/app + COPY ./flow /usr/app + """ + with tempfile.TemporaryDirectory() as tmp_path: + ### a. Creating archive with context (flow files + Dockerfile) for Docker build API + os.makedirs(f"{tmp_path}/build") + with open(f"{tmp_path}/build/Dockerfile", "w+") as the_file: + the_file.write(dockerfile) + shutil.copytree("/usr/app", f"{tmp_path}/build/flow") + with tarfile.open(f"{tmp_path}/flow.tar", "w") as tar: + tar.add(f"{tmp_path}/build", arcname=".") + ### b. Build image with context + with open(f"{tmp_path}/flow.tar", "rb") as fh: + docker_build_archive = BytesIO(fh.read()) + cli = APIClient(base_url="unix:///var/run/docker.sock") + for line in cli.build( + fileobj=docker_build_archive, custom_context=True, rm=True, tag=flow_image + ): + print(line, flush=True) + for line in cli.push(flow_image, stream=True, decode=True): + print(line, flush=True) + + ## 2. Registering flow + dockerhub = DockerRegistry( + username=os.environ.get("REGISTRY_USERNAME"), + password=os.environ.get("REGISTRY_PASSWORD"), + reauth=True, + registry_url=f"{os.environ.get('REGISTRY_SCHEME')}://{os.environ.get('REGISTRY_ENDPOINT')}", + ) + dockerhub.save("docker-storage", overwrite=True) + docker_block = DockerContainer( + image=flow_image, + image_registry=dockerhub, + ) + docker_block.save("docker-storage", overwrite=True) + + deployment = Deployment.build_from_flow( + name="get_weather_docker_example", + flow=get_paris_weather, + infrastructure=docker_block, # storage block is automatically detected from https://github.com/PrefectHQ/prefect/pull/6574/files + work_queue_name="flows-example-queue-docker", + path="/usr/app", + ) + deployment.apply() diff --git a/src/prefect-docker-compose-main/client_docker/docker-compose.yml b/src/prefect-docker-compose-main/client_docker/docker-compose.yml new file mode 100644 index 0000000..5f1f724 --- /dev/null +++ b/src/prefect-docker-compose-main/client_docker/docker-compose.yml @@ -0,0 +1,42 @@ +version: "3.8" + +services: + + registry: + restart: always + image: registry:2.8.1 + ports: + - 5000:5000 + volumes: + - ./registry/auth:/auth + - registry_data:/data + environment: + REGISTRY_AUTH: htpasswd + REGISTRY_AUTH_HTPASSWD_REALM: Registry + REGISTRY_AUTH_HTPASSWD_PATH: /auth/.htpasswd + REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data + + # The script should have access to Docker in order to register + # the Dockerized script (`execution.Dockerfile`) in a + # Docker image later used by the Prefect agent. + weather: + build: . + privileged: true # forced for Docker DinD + environment: + PREFECT_API_URL: "http://172.17.0.1:4200/api" + REGISTRY_ENDPOINT: "172.17.0.1:5000" + REGISTRY_SCHEME: "http" + REGISTRY_USERNAME: myusername + REGISTRY_PASSWORD: test + volumes: + - ./app:/usr/app:ro + - type: bind + source: /var/run/docker.sock + target: /var/run/docker.sock + read_only: true + depends_on: + - registry + +volumes: + registry_data: + flows_docker: diff --git a/src/prefect-docker-compose-main/client_docker/entrypoint.sh b/src/prefect-docker-compose-main/client_docker/entrypoint.sh new file mode 100644 index 0000000..5828727 --- /dev/null +++ b/src/prefect-docker-compose-main/client_docker/entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/sh +docker login -u=${REGISTRY_USERNAME} -p=${REGISTRY_PASSWORD} "${REGISTRY_SCHEME}://${REGISTRY_ENDPOINT}" +python3 /usr/app/weather.py diff --git a/src/prefect-docker-compose-main/client_docker/execution.Dockerfile b/src/prefect-docker-compose-main/client_docker/execution.Dockerfile new file mode 100644 index 0000000..60e049c --- /dev/null +++ b/src/prefect-docker-compose-main/client_docker/execution.Dockerfile @@ -0,0 +1,4 @@ +FROM python:3.10 + +RUN apt update && apt install uuid -y +RUN pip3 install --upgrade pip && pip3 install prefect==2.4.2 diff --git a/src/prefect-docker-compose-main/client_s3/Dockerfile b/src/prefect-docker-compose-main/client_s3/Dockerfile new file mode 100644 index 0000000..b526131 --- /dev/null +++ b/src/prefect-docker-compose-main/client_s3/Dockerfile @@ -0,0 +1,6 @@ +FROM python:3.10 + +RUN apt update && apt install uuid -y +RUN pip install prefect==2.4.2 psycopg2-binary==2.9.3 s3fs==2022.8.2 minio==7.1.11 + +WORKDIR /usr/app diff --git a/src/prefect-docker-compose-main/client_s3/app/weather.py b/src/prefect-docker-compose-main/client_s3/app/weather.py new file mode 100644 index 0000000..35dfb7a --- /dev/null +++ b/src/prefect-docker-compose-main/client_s3/app/weather.py @@ -0,0 +1,148 @@ +# A simple example to demonstrate Prefect is working as expected +# Works with a local folder shared with the agents (/root/.prefect/flows by default). + +import io +import json +import os +import uuid +from datetime import datetime + +import requests +from minio import Minio +from minio.error import S3Error +from prefect import flow, get_run_logger, task +from prefect.deployments import Deployment +from prefect.filesystems import RemoteFileSystem + +# --- Flow definition + + +@task +def create_bucket( + minio_endpoint, + minio_access_key, + minio_secret_key, + minio_use_ssl, + bucket_name, +): + client = Minio( + minio_endpoint, minio_access_key, minio_secret_key, secure=minio_use_ssl + ) + try: + client.make_bucket(bucket_name) + except S3Error as ex: + if ex.code != "BucketAlreadyOwnedByYou": + raise ex + print("Flows bucket already exist, skipping.", flush=True) + + +@task +def get_city_coordinates(city: str): + logger = get_run_logger() + cities = {"Paris": (2.3510, 48.8567)} + logger.info("Getting {}'s coordinates".format(city)) + return cities[city] + + +@task +def get_weather(longitude: float, latitude: float): + logger = get_run_logger() + logger.info(f"Getting weather of latitude={latitude} and longitude={longitude}") + api_endpoint = f"https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}&hourly=temperature_2m" + response = requests.get(api_endpoint) + if response.status_code == 200: + weather_data = json.loads(response.text) + logger.debug(weather_data) + return weather_data + else: + raise Exception("Failed to query " + api_endpoint) + + +@task +def add_text_to_bucket( + content: str, + minio_endpoint, + minio_access_key, + minio_secret_key, + minio_use_ssl, + bucket_name, +): + client = Minio( + minio_endpoint, minio_access_key, minio_secret_key, secure=minio_use_ssl + ) + content_json = json.dumps(content) + client.put_object( + object_name=f"{datetime.today().strftime('%Y%m%d%H%M%S')}/weather.txt", + bucket_name=bucket_name, + data=io.BytesIO(str.encode(content_json)), + length=len(content_json), + content_type="text/plain", + ) + + +@flow(name="get_paris_weather_s3") +def get_paris_weather( + minio_endpoint: str, + minio_access_key: str, + minio_secret_key: str, + minio_use_ssl: bool, + artifacts_bucket_name: str, +): + city_coordinates = get_city_coordinates("Paris") + weather_content = get_weather(city_coordinates[0], city_coordinates[1]) + create_bucket( + minio_endpoint, + minio_access_key, + minio_secret_key, + minio_use_ssl, + artifacts_bucket_name, + ) + add_text_to_bucket( + weather_content, + minio_endpoint, + minio_access_key, + minio_secret_key, + minio_use_ssl, + artifacts_bucket_name, + ) + return True + + +# --- Deployment definition + +if __name__ == "__main__": + bucket_name = os.environ.get("MINIO_PREFECT_FLOWS_BUCKET_NAME") + artifacts_bucket_name = os.environ.get("MINIO_PREFECT_ARTIFACTS_BUCKET_NAME") + minio_endpoint = os.environ.get("MINIO_ENDPOINT") + minio_use_ssl = os.environ.get("MINIO_USE_SSL") == "true" + minio_scheme = "https" if minio_use_ssl else "http" + minio_access_key = os.environ.get("MINIO_ACCESS_KEY") + minio_secret_key = os.environ.get("MINIO_SECRET_KEY") + + flow_identifier = datetime.today().strftime("%Y%m%d%H%M%S-") + str(uuid.uuid4()) + block_storage = RemoteFileSystem( + basepath=f"s3://{bucket_name}/{flow_identifier}", + key_type="hash", + settings=dict( + use_ssl=minio_use_ssl, + key=minio_access_key, + secret=minio_secret_key, + client_kwargs=dict(endpoint_url=f"{minio_scheme}://{minio_endpoint}"), + ), + ) + block_storage.save("s3-storage", overwrite=True) + + deployment = Deployment.build_from_flow( + name="get_weather_s3_example", + flow=get_paris_weather, + storage=RemoteFileSystem.load("s3-storage"), + work_queue_name="flows-example-queue", + parameters={ + "minio_endpoint": minio_endpoint, + "minio_access_key": minio_access_key, + "minio_secret_key": minio_secret_key, + "minio_use_ssl": minio_use_ssl, + "artifacts_bucket_name": artifacts_bucket_name, + }, + ) + deployment.apply() diff --git a/src/prefect-docker-compose-main/client_s3/docker-compose.yml b/src/prefect-docker-compose-main/client_s3/docker-compose.yml new file mode 100644 index 0000000..494046a --- /dev/null +++ b/src/prefect-docker-compose-main/client_s3/docker-compose.yml @@ -0,0 +1,37 @@ +version: "3.7" + +services: + + minio: + image: minio/minio:RELEASE.2022-09-07T22-25-02Z + command: server --console-address ":9001" /data + ports: + - 9000:9000 + - 9001:9001 + volumes: + - /srv/docker/prefect/minio:/data + environment: + MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY} + MINIO_SECRET_KEY: ${MINIO_SECRET_KEY} + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 5s + timeout: 3s + retries: 10 + + weather: + build: . + command: python3 /usr/app/weather.py + volumes: + - ./app:/usr/app:ro + environment: + PREFECT_API_URL: "http://172.17.0.1:4200/api" + MINIO_USE_SSL: ${MINIO_USE_SSL} + MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY} + MINIO_SECRET_KEY: ${MINIO_SECRET_KEY} + MINIO_ENDPOINT: ${MINIO_ENDPOINT} # Must be accessible from Agent + MINIO_PREFECT_FLOWS_BUCKET_NAME: ${MINIO_PREFECT_FLOWS_BUCKET_NAME} + MINIO_PREFECT_ARTIFACTS_BUCKET_NAME: ${MINIO_PREFECT_ARTIFACTS_BUCKET_NAME} + depends_on: + minio: + condition: service_healthy diff --git a/src/prefect-docker-compose-main/docker_interface.png b/src/prefect-docker-compose-main/docker_interface.png new file mode 100644 index 0000000..0cb3922 Binary files /dev/null and b/src/prefect-docker-compose-main/docker_interface.png differ diff --git a/src/prefect-docker-compose-main/prefect_schema_principle.drawio b/src/prefect-docker-compose-main/prefect_schema_principle.drawio new file mode 100644 index 0000000..81aa1ca --- /dev/null +++ b/src/prefect-docker-compose-main/prefect_schema_principle.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/src/prefect-docker-compose-main/prefect_schema_principle.jpg b/src/prefect-docker-compose-main/prefect_schema_principle.jpg new file mode 100644 index 0000000..d067574 Binary files /dev/null and b/src/prefect-docker-compose-main/prefect_schema_principle.jpg differ diff --git a/src/prefect-docker-compose-main/server/Dockerfile b/src/prefect-docker-compose-main/server/Dockerfile new file mode 100644 index 0000000..8d119f7 --- /dev/null +++ b/src/prefect-docker-compose-main/server/Dockerfile @@ -0,0 +1,4 @@ +FROM prefecthq/prefect:2.4.2-python3.10 + +RUN apt update && \ + pip install psycopg2-binary==2.9.3 s3fs==2022.8.2 diff --git a/src/prefect-docker-compose-main/server/docker-compose.yml b/src/prefect-docker-compose-main/server/docker-compose.yml new file mode 100644 index 0000000..c3c3d6a --- /dev/null +++ b/src/prefect-docker-compose-main/server/docker-compose.yml @@ -0,0 +1,48 @@ +version: "3.7" + +services: + + postgres: + command: + - postgres + - -c + - max_connections=150 + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} + volumes: + - postgres:/var/lib/postgresql/data + healthcheck: + interval: 10s + retries: 60 + start_period: 2s + test: pg_isready -q -d $${POSTGRES_DB} -U $${POSTGRES_USER} | grep "accepting connections" || exit 1 + timeout: 2s + image: postgres:14 + restart: always + + orion: + restart: always + build: . + + command: prefect orion start + ports: + - 4200:4200 + depends_on: + postgres: + condition: service_started + volumes: + - prefect_data:/root/.prefect + - prefect_flows:/flows + environment: + PREFECT_ORION_API_HOST: 0.0.0.0 + PREFECT_ORION_DATABASE_CONNECTION_URL: ${DB_CONNECTION_URL} + PREFECT_ORION_ANALYTICS_ENABLED: "false" + PREFECT_LOGGING_SERVER_LEVEL: WARNING + PREFECT_API_URL: ${PREFECT_API_URL} + +volumes: + postgres: + prefect_data: + prefect_flows: \ No newline at end of file diff --git a/src/vscode-dotnet-project/CODE_OF_CONDUCT.md b/src/vscode-dotnet-project/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..f9ba8cf --- /dev/null +++ b/src/vscode-dotnet-project/CODE_OF_CONDUCT.md @@ -0,0 +1,9 @@ +# Microsoft Open Source Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). + +Resources: + +- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) +- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) +- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns diff --git a/src/vscode-dotnet-project/LICENSE b/src/vscode-dotnet-project/LICENSE new file mode 100644 index 0000000..4b1ad51 --- /dev/null +++ b/src/vscode-dotnet-project/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/src/vscode-dotnet-project/Program.cs b/src/vscode-dotnet-project/Program.cs new file mode 100644 index 0000000..ff8b47e --- /dev/null +++ b/src/vscode-dotnet-project/Program.cs @@ -0,0 +1,34 @@ +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.Urls.Add("http://localhost:5000"); + +app.MapGet("/", () => "Hello World!"); + +app.MapGet("/{cityName}/weather", GetWeatherByCity); + +app.Run(); + + +Weather GetWeatherByCity(string cityName) +{ + app.Logger.LogInformation($"Weather requested for {cityName}."); + var weather = new Weather(cityName); + return weather; +} + +public record Weather +{ + public string City { get; set; } + + public Weather(string city) + { + City = city; + Conditions = "Cloudy"; + // Temperature here is in celsius degrees, hence the 0-40 range. + Temperature = new Random().Next(0,40).ToString(); + } + + public string Conditions { get; set; } + public string Temperature { get; set; } +} \ No newline at end of file diff --git a/src/vscode-dotnet-project/README.md b/src/vscode-dotnet-project/README.md new file mode 100644 index 0000000..d239cfa --- /dev/null +++ b/src/vscode-dotnet-project/README.md @@ -0,0 +1,109 @@ +# Try Out Development Containers: .NET + +[![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode-remote-try-dotnet) + + +A **development container** is a running container with a well-defined tool/runtime stack and its prerequisites. You can try out development containers with **[GitHub Codespaces](https://github.com/features/codespaces)** or **[Visual Studio Code Dev Containers](https://aka.ms/vscode-remote/containers)**. + +This is a sample project that lets you try out either option in a few easy steps. We have a variety of other [vscode-remote-try-*](https://github.com/search?q=org%3Amicrosoft+vscode-remote-try-&type=Repositories) sample projects, too. + +> **Note:** If you already have a Codespace or dev container, you can jump to the [Things to try](#things-to-try) section. + +## Setting up the development container + +### GitHub Codespaces +Follow these steps to open this sample in a Codespace: +1. Click the **Code** drop-down menu. +2. Click on the **Codespaces** tab. +3. Click **Create codespace on main** . + +For more info, check out the [GitHub documentation](https://docs.github.com/en/free-pro-team@latest/github/developing-online-with-codespaces/creating-a-codespace#creating-a-codespace). + +### VS Code Dev Containers + +If you already have VS Code and Docker installed, you can click the badge above or [here](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode-remote-try-dotnet) to get started. Clicking these links will cause VS Code to automatically install the Dev Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use. + +Follow these steps to open this sample in a container using the VS Code Dev Containers extension: + +1. If this is your first time using a development container, please ensure your system meets the pre-reqs (i.e. have Docker installed) in the [getting started steps](https://aka.ms/vscode-remote/containers/getting-started). + +2. To use this repository, you can either open the repository in an isolated Docker volume: + + - Press F1 and select the **Dev Containers: Try a Sample...** command. + - Choose the ".NET Core" sample, wait for the container to start, and try things out! + > **Note:** Under the hood, this will use the **Dev Containers: Clone Repository in Container Volume...** command to clone the source code in a Docker volume instead of the local filesystem. [Volumes](https://docs.docker.com/storage/volumes/) are the preferred mechanism for persisting container data. + + Or open a locally cloned copy of the code: + + - Clone this repository to your local filesystem. + - Press F1 and select the **Dev Containers: Open Folder in Container...** command. + - Select the cloned copy of this folder, wait for the container to start, and try things out! + +3. If you want to enable **HTTPS**, see [enabling HTTPS](#enabling-https) to reuse your local development cert in the container. + +## Things to try + +Once you have this sample opened, you'll be able to work with it like you would locally. + +Some things to try: + +1. **Restore Packages:** When notified by the C# extension to install packages, click Restore to trigger the process from inside the container! You can also execute `dotnet restore` command in a terminal. + +2. **Edit:** + - Open `Program.cs` + - Try adding some code and check out the language features. + - Make a spelling mistake and notice it is detected. The [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) extension was automatically installed because it is referenced in `.devcontainer/devcontainer.json`. + - Also notice that the [C#](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) extension is installed. Tools are installed in the `mcr.microsoft.com/devcontainers/dotnet` image and Dev Container settings and metadata are automatically picked up from [image labels](https://containers.dev/implementors/reference/#labels). + + +4. **Build, Run, and Debug:** + - Open `Program.cs` + - Add a breakpoint (e.g. on line 16). + - Press F5 to launch the app in the container. + - Navigate to the weather endpoint, for example, [http://localhost:5000/paris/weather](http://localhost:5000/paris/weather). + - Once the breakpoint is hit, try hovering over variables, examining locals, and more. + - Continue (F5). You can connect to the server in the container by either: + - Clicking on `Open in Browser` in the notification telling you: `Your service running on port 5000 is available`. + - Clicking the globe icon in the 'Ports' view. The 'Ports' view gives you an organized table of your forwarded ports, and you can access it with the command **Ports: Focus on Ports View**. + - Notice port 5000 in the 'Ports' view is labeled "Hello Remote World." In `devcontainer.json`, you can set `"portsAttributes"`, such as a label for your forwarded ports and the action to be taken when the port is autoforwarded. + + > **Note:** In Dev Containers, you can access your app at `http://localhost:5000` in a local browser. But in a browser-based Codespace, you must click the link from the notification or the `Ports` view so that the service handles port forwarding in the browser and generates the correct URL. + +5. **Rebuild or update your container** + + You may want to make changes to your container, such as installing a different version of a software or forwarding a new port. You'll rebuild your container for your changes to take effect. + + **Open browser automatically:** As an example change, let's update the `portsAttributes` in the `.devcontainer/devcontainer.json` file to open a browser when our port is automatically forwarded. + + - Open the `.devcontainer/devcontainer.json` file. + - Modify the `"onAutoForward"` attribute in your `portsAttributes` from `"notify"` to `"openBrowser"`. + - Press F1 and select the **Dev Containers: Rebuild Container** or **Codespaces: Rebuild Container** command so the modifications are picked up. + +5. **Install Node.js using a Dev Container Feature:** + - Press F1 and select the **Dev Containers: Configure Container Features...** or **Codespaces: Configure Container Features...** command. + - Type "node" in the text box at the top. + - Check the check box next to "Node.js (via nvm) and yarn" (published by devcontainers) + - Click OK + - Press F1 and select the **Dev Containers: Rebuild Container** or **Codespaces: Rebuild Container** command so the modifications are picked up. + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. + +When you submit a pull request, a CLA bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +## Trademarks + +This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft +trademarks or logos is subject to and must follow +[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). +Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. +Any use of third-party trademarks or logos are subject to those third-party's policies. diff --git a/src/vscode-dotnet-project/SECURITY.md b/src/vscode-dotnet-project/SECURITY.md new file mode 100644 index 0000000..e138ec5 --- /dev/null +++ b/src/vscode-dotnet-project/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + + diff --git a/src/vscode-dotnet-project/appsettings.Development.json b/src/vscode-dotnet-project/appsettings.Development.json new file mode 100644 index 0000000..ff66ba6 --- /dev/null +++ b/src/vscode-dotnet-project/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/vscode-dotnet-project/appsettings.HttpsDevelopment.json b/src/vscode-dotnet-project/appsettings.HttpsDevelopment.json new file mode 100644 index 0000000..8f41d8b --- /dev/null +++ b/src/vscode-dotnet-project/appsettings.HttpsDevelopment.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} \ No newline at end of file diff --git a/src/vscode-dotnet-project/appsettings.json b/src/vscode-dotnet-project/appsettings.json new file mode 100644 index 0000000..4d56694 --- /dev/null +++ b/src/vscode-dotnet-project/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/src/vscode-dotnet-project/vscode-remote-try-dotnet.csproj b/src/vscode-dotnet-project/vscode-remote-try-dotnet.csproj new file mode 100644 index 0000000..06fd153 --- /dev/null +++ b/src/vscode-dotnet-project/vscode-remote-try-dotnet.csproj @@ -0,0 +1,10 @@ + + + + net7.0 + enable + enable + vscode_remote_try_dotnet + + +