diff --git a/.github/workflows/lightsail-deploy-web-service.yml b/.github/workflows/lightsail-deploy-web-service.yml new file mode 100644 index 0000000..50e462a --- /dev/null +++ b/.github/workflows/lightsail-deploy-web-service.yml @@ -0,0 +1,115 @@ +name: Deploy Lightsail Containers + +on: + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: + inputs: + service_name_1: + description: "The name of the first Lightsail service" + required: true + default: "diaspora-web-service" + container_name_1: + description: "The name of the first Docker container" + required: true + default: "diaspora-web-service-container" + dockerfile_path_1: + description: "The path to the first Dockerfile" + required: true + default: "web_service/Dockerfile" + service_name_2: + description: "The name of the second Lightsail service" + required: true + default: "diaspora-action-provider" + container_name_2: + description: "The name of the second Docker container" + required: true + default: "diaspora-action-provider-container" + dockerfile_path_2: + description: "The path to the second Dockerfile" + required: true + default: "action_provider/Dockerfile" + +jobs: + deploy-lightsail-containers: + runs-on: ubuntu-latest + + strategy: + matrix: + include: + - service_name: ${{ github.event.inputs.service_name_1 || 'diaspora-web-service' }} + container_name: ${{ github.event.inputs.container_name_1 || 'diaspora-web-service-container' }} + dockerfile_path: ${{ github.event.inputs.dockerfile_path_1 || 'web_service/Dockerfile' }} + - service_name: ${{ github.event.inputs.service_name_2 || 'diaspora-action-provider' }} + container_name: ${{ github.event.inputs.container_name_2 || 'diaspora-action-provider-container' }} + dockerfile_path: ${{ github.event.inputs.dockerfile_path_2 || 'action_provider/Dockerfile' }} + + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + + - name: Verify AWS credential + run: | + aws sts get-caller-identity + + - name: Install AWS Lightsail plugin + run: | + sudo curl "https://s3.us-west-2.amazonaws.com/lightsailctl/latest/linux-amd64/lightsailctl" -o "/usr/local/bin/lightsailctl" + sudo chmod +x /usr/local/bin/lightsailctl + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Build Docker container for AWS Lightsail + run: | + echo "SERVICE NAME" + echo ${{ matrix.service_name }} + + echo "CONTAINER NAME" + echo ${{ matrix.container_name }} + + echo "DOCKERFILE PATH" + echo ${{ matrix.dockerfile_path }} + + docker build -t ${{ matrix.container_name }} -f ${{ matrix.dockerfile_path }} . + docker images + + - name: Idempotently Create Lightsail container service + continue-on-error: true + run: | + aws lightsail create-container-service --region us-east-1 --service-name ${{ matrix.service_name }} --power small --scale 1 + + - name: Push Docker image to Lightsail and deploy + run: | + output=$(aws lightsail push-container-image --region us-east-1 --service-name ${{ matrix.service_name }} --label ${{ matrix.container_name }} --image ${{ matrix.container_name }}) + image_name=$(echo "$output" | sed -n 's/.*Refer to this image as "\(.*\)" in deployments.*/\1/p') + + echo "IMAGE NAME" + echo "$image_name" + + containers=$(jq -n --arg image_name "$image_name" '{ + "flask": { + "image": $image_name, + "ports": { + "8000": "HTTP" + } + } + }') + + public_endpoint=$(jq -n '{ + "containerName": "flask", + "containerPort": 8000 + }') + + aws lightsail create-container-service-deployment --region us-east-1 \ + --service-name ${{ matrix.service_name }} \ + --containers "$containers" \ + --public-endpoint "$public_endpoint" diff --git a/.github/workflows/lightsail-deploy.yml b/.github/workflows/lightsail-deploy.yml deleted file mode 100644 index 0af260e..0000000 --- a/.github/workflows/lightsail-deploy.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Configure AWS Credentials - -on: - push: - branches: - - lightsail-deploy - pull_request: - branches: - - lightsail-deploy - -jobs: - configure-aws-credentials: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-1 - - - name: Verify AWS configuration - run: | - aws sts get-caller-identity diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8789f1d --- /dev/null +++ b/.gitignore @@ -0,0 +1,135 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# Diaspora Web Service and Action Provider +secrets.sh +nohup.out +*.pyc +*venv* diff --git a/README.md b/README.md index 204db3a..f4c4bde 100644 --- a/README.md +++ b/README.md @@ -1 +1,90 @@ -# diaspora-service \ No newline at end of file +# diaspora-service + +docker build -t diaspora-app -f lightsail/Dockerfile . + +docker run -p 8000:8000 diaspora-app + +aws lightsail create-container-service --service-name diaspora-app --power micro --scale 1 + +aws lightsail push-container-image --region us-east-1 --service-name diaspora-app --label diaspora-app --image diaspora-app +# Refer to this image as ":diaspora-app.diaspora-app.22" in deployments. + +aws lightsail create-container-service-deployment --region us-east-1 --cli-input-json + + + +aws lightsail create-container-service --generate-cli-skeleton + + + +docker build -t diaspora-app2 -f Dockerfile . +docker run -p 8000:8000 diaspora-app2 + +aws lightsail create-container-service --region us-east-1 --service-name diaspora-app2 --power small --scale 1 +aws lightsail push-container-image --region us-east-1 --service-name diaspora-app2 --label diaspora-app2 --image diaspora-app2 --no-paginate --output json + +aws lightsail create-container-service-deployment --region us-east-1 \ + --service-name diaspora-app2 \ + --containers '{ + "flask": { + "image": ":diaspora-app2.diaspora-app2.26", + "ports": { + "8000": "HTTP" + } + } + }' \ + --public-endpoint '{ + "containerName": "flask", + "containerPort": 8000 + }' + +```bash +# current_container="$service_name-$(openssl rand -base64 12 | tr 'A-Z' 'a-z' | tr -dc 'a-z0-9')" + + +service_name="diaspora-service" +current_container="$service_name-container" +echo $current_container +docker build -t $current_container -f Dockerfile . +docker run -p 8000:8000 $current_container + +aws lightsail create-container-service --region us-east-1 --service-name $service_name --power small --scale 1 +output=$(aws lightsail push-container-image --region us-east-1 --service-name $service_name --label $current_container --image $current_container) +image_name=$(echo "$output" | sed -n 's/.*Refer to this image as "\(.*\)" in deployments.*/\1/p') +echo "$image_name" + +containers=$(jq -n --arg image_name "$image_name" '{ + "flask": { + "image": $image_name, + "ports": { + "8000": "HTTP" + } + } +}') + +public_endpoint=$(jq -n '{ + "containerName": "flask", + "containerPort": 8000 +}') + +aws lightsail create-container-service-deployment --region us-east-1 \ + --service-name $service_name \ + --containers "$containers" \ + --public-endpoint "$public_endpoint" + + + + + +service_name="diaspora-web-service" +current_container="$service_name-container" +docker build -t $current_container -f web_service/Dockerfile . +docker run -p 8000:8000 $current_container + + +service_name="diaspora-action-provider" +current_container="$service_name-container" +docker build -t $current_container -f action_provider/Dockerfile . +docker run -p 8000:8000 $current_container +``` + diff --git a/action_provider/Dockerfile b/action_provider/Dockerfile new file mode 100644 index 0000000..e1716d1 --- /dev/null +++ b/action_provider/Dockerfile @@ -0,0 +1,12 @@ +FROM --platform=linux/amd64 python:3.11 + +EXPOSE 8000/tcp + +WORKDIR /diaspora-action-provider + +COPY action_provider action_provider +COPY pyproject.toml . + +RUN pip install . + +CMD [ "python", "action_provider/main.py" ] \ No newline at end of file diff --git a/action_provider/main.py b/action_provider/main.py new file mode 100644 index 0000000..3137968 --- /dev/null +++ b/action_provider/main.py @@ -0,0 +1,9 @@ +from flask import Flask +app = Flask(__name__) + +@app.route('/') +def hello_world(): + return "Hello, World from Action Provider" + +if __name__ == "__main__": + app.run(host='0.0.0.0', port=8000) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..5dff2e8 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,38 @@ +[build-system] +requires = ["setuptools >= 61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "diaspora-service" +version = "0.0.1" +dependencies = [ + "aws-msk-iam-sasl-signer-python", + "boto3", + "diaspora-event-sdk", + "fastapi", + "flask", + "globus_action_provider_tools", + "globus_sdk", + "gunicorn", + "jinja2", + "kafka-python", + "requests", + "uvicorn", +] + +requires-python = ">=3.8" +authors = [{ name = "Haochen Pan" }, { email = "haochenpan@uchicago.edu" }] +description = "Diaspora Service" +readme = "README.md" +license = { text = "MIT" } +classifiers = [ + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", +] + +[project.urls] +homepage = "https://diaspora-project.github.io/" +repository = "https://github.com/haochenpan/diaspora-service" + +[tool.setuptools.packages.find] +where = ["app", "web_service"] diff --git a/web_service/Dockerfile b/web_service/Dockerfile new file mode 100644 index 0000000..0b555ea --- /dev/null +++ b/web_service/Dockerfile @@ -0,0 +1,12 @@ +FROM --platform=linux/amd64 python:3.11 + +EXPOSE 8000/tcp + +WORKDIR /diaspora-web-service + +COPY web_service web_service +COPY pyproject.toml . + +RUN pip install . + +CMD [ "uvicorn", "web_service.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload" ] diff --git a/web_service/main.py b/web_service/main.py new file mode 100644 index 0000000..48488cf --- /dev/null +++ b/web_service/main.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def root(): + return {"message": "Hello World from Web Servic Today"} \ No newline at end of file