From 045aeaed92284f81b31ec130d91423fdf2ce417a Mon Sep 17 00:00:00 2001 From: David Torralba Goitia Date: Wed, 13 Mar 2019 21:56:38 +0000 Subject: [PATCH] helm: add mosbot chart - Use the Common chart - Add instructions for the Helm chart - Upgrade Docker base image python version - Update Dockerfile to install mosbot correctly - Remove unneded images from docker-compose.yml - Fix reStructuredText markup in docs --- Dockerfile | 13 +++--- README.rst | 63 +++++++++++++++++++----------- docker-compose.yml | 16 +++----- helm/Chart.yaml | 15 +++++++ helm/charts/common-0.0.5.tgz | Bin 0 -> 8347 bytes helm/charts/postgresql-3.13.1.tgz | Bin 0 -> 17904 bytes helm/requirements.lock | 9 +++++ helm/requirements.yaml | 7 ++++ helm/templates/NOTES.txt | 21 ++++++++++ helm/templates/_helpers.tpl | 27 +++++++++++++ helm/templates/deployment.yaml | 20 ++++++++++ helm/values.yaml | 29 ++++++++++++++ setup.py | 2 +- 13 files changed, 181 insertions(+), 41 deletions(-) create mode 100644 helm/Chart.yaml create mode 100644 helm/charts/common-0.0.5.tgz create mode 100644 helm/charts/postgresql-3.13.1.tgz create mode 100644 helm/requirements.lock create mode 100644 helm/requirements.yaml create mode 100644 helm/templates/NOTES.txt create mode 100644 helm/templates/_helpers.tpl create mode 100644 helm/templates/deployment.yaml create mode 100644 helm/values.yaml diff --git a/Dockerfile b/Dockerfile index 4fca59f..fb1a7e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,14 @@ -FROM python:3.6-slim +FROM python:3.7-slim WORKDIR /usr/src/app RUN pip install pipenv COPY Pipfile Pipfile.lock ./ -RUN pipenv install - -COPY dist/abot-0.0.1a0.tar.gz ./mosbot.tar.gz -RUN tar xf mosbot.tar.gz --strip-components=1 +RUN pipenv sync +COPY setup.cfg setup.py README.rst alembic.ini ./ +COPY alembic ./alembic +COPY mosbot ./mosbot RUN pipenv run python setup.py develop -CMD ["pipenv", "run", "bot", "run"] - +CMD ["/bin/sh", "-c", "pipenv run alembic upgrade head && pipenv run bot run"] diff --git a/README.rst b/README.rst index 5f49022..788b5bd 100644 --- a/README.rst +++ b/README.rst @@ -1,55 +1,56 @@ + How to get started ------------------ 1. Install *Pipenv* at a system level - + If you are not using it for your projects, you should. *Pipenv* is a mix between *pip* and *virtualenv* (it uses both of them below) and basically manages everything. You can probably find *Pipenv* packaged, check their webpage for installation steps. 2. Install dependencies - + In a command line, navigate to the current project directory and install the dependencies by running one of the commands below. - * To use the bot: `pipenv install` + * To use the bot: ``pipenv install`` - * To develop: `pipenv install -d` + * To develop: ``pipenv install -d`` If these steps don't work, please report it so that I can update these instructions with relevant steps. 3. Install *mostbot* as a package - - Run the command `python setup.py develop`. You can also do `python setup.py install`, but it's better to keep the - installation linked to this directory instead of having `setuptools` package and install the bot separately. If you + + Run the command ``python setup.py develop``. You can also do ``python setup.py install``, but it's better to keep the + installation linked to this directory instead of having ``setuptools`` package and install the bot separately. If you have doubts on what I just said, https://stackoverflow.com/questions/19048732/python-setup-py-develop-vs-install 4. Install a database - + Apart from the bot code, you also need a database to link the bot to. You can link it to whatever *PostgreSQL* database you want, but I would recommend you to run a local instance. - + Using *Docker* and *Docker Compose* is a really good way to run packaged software. There are complete guides on the internet about how to run them, but for the basics: 1. Install *Docker* either using your package manager or as suggested in *Docker*'s official webpage. By the way, the official website method is just a Python script, so you can also install it with *pip* (I would discourage this option). - + 2. Install *Docker Compose*. Same thing as *Docker*: user either package manager or the official webpage script. - + 3. Open another terminal in this folder. This new terminal will be used all the time to maintain up the database while your bot is running. There are other ways to run the database in the background, but I recommend this one. - - 4. In the new terminal, run `docker-compose up` to download and run the packaged software (the *PostgreSQL* + + 4. In the new terminal, run ``docker-compose up`` to download and run the packaged software (the *PostgreSQL* database in this case). - - 5. Run `alembic upgrade head` to create the database structure by setting up all the database tables, etc. + + 5. Run ``alembic upgrade head`` to create the database structure by setting up all the database tables, etc. 5. Launch *mosbot* - - Go back to the first terminal, and run `bot` to launch. The output of the command should be self explanatory. + + Go back to the first terminal, and run ``bot`` to launch. The output of the command should be self explanatory. @@ -59,20 +60,20 @@ Project structure This is a brief outline to cover the basics of the project structure: * The more inner layer and the thing that most defines the bot is the Data Model. This are the Entities that we - manage, and they are in `mosbot/db.py`. + manage, and they are in ``mosbot/db.py``. * From there, because we have no ORM at the moment (asyncio doesn't have an async ORM yet), we have all the functions - and queries that operate on the data in `mosbot/query.py`. + and queries that operate on the data in ``mosbot/query.py``. * Now you should be able to gather/write data and make some operations. There are some operations that are not as "simple" as the queries, and these are the "usecases" where you have a whole flow of queries and data transformation. - The place where these are stored is in `mosbot/usecase.py` + The place where these are stored is in ``mosbot/usecase.py`` * Finally, in the most outer layer, you have the two main "interfaces", this is where we receive the data from the - `abot` library and we have the handlers and commands. The files are, `mosbot/handler.py` for event handlers and - `mosbot/command.py` for the commands. + ``abot`` library and we have the handlers and commands. The files are, ``mosbot/handler.py`` for event handlers and + ``mosbot/command.py`` for the commands. -* There are two other files, that are "transversal" that are the `mosbot/utils.py` and `mosbot/config.py`. +* There are two other files, that are "transversal" that are the ``mosbot/utils.py`` and ``mosbot/config.py``. You should think of this architecture (file structure/function dependencies) as an onion. The idea is that the most @@ -91,6 +92,22 @@ Further recommendations rest of alternatives. Of course, you are free to choose whichever editor you want. +Using the Helm chart +-------------------- + +1. Fetch/update chart dependencies: + + .. code-block:: bash + + helm dependency update ./helm + + +2. Install mosbot chart: + + .. code-block:: bash + + helm install ./helm + Contributions ------------- diff --git a/docker-compose.yml b/docker-compose.yml index f5f767b..0bcbe57 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,16 +1,12 @@ version: '2' services: - rabbitmq: - image: rabbitmq:management - ports: - - "15672:15672" - - "5672:5672" - - "4369:4369" - redis: - image: redis - ports: - - "6379:6379" postgres: image: mdillon/postgis ports: - "5432:5432" + # mosbot: + # image: dtgoitia/mosbot:latest + # environment: + # DATABASE_URL: postgresql://postgres@postgres/postgres + # depends_on: + # - postgres diff --git a/helm/Chart.yaml b/helm/Chart.yaml new file mode 100644 index 0000000..554c777 --- /dev/null +++ b/helm/Chart.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +name: mosbot +description: Master of Soundtrack bot +version: 0.0.1 +appVersion: 0.0.1 +home: https://github.com/txomon/mosbot +sources: + - https://github.com/txomon/mosbot +keywords: + - bot + - mosbot + - master of soundtrack +maintainers: + - name: txomon + email: javierdo1@gmail.com diff --git a/helm/charts/common-0.0.5.tgz b/helm/charts/common-0.0.5.tgz new file mode 100644 index 0000000000000000000000000000000000000000..ca0a64ae31477b801f86d8e7ddd4d0adc254deaa GIT binary patch literal 8347 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 literal 0 HcmV?d00001 diff --git a/helm/charts/postgresql-3.13.1.tgz b/helm/charts/postgresql-3.13.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..b9feaf6ff460f8d35e5c1c202bb4540992a557f5 GIT binary patch literal 17904 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 V4^PYU{{jF2|Nqz#cryU70RV+k+ll}H literal 0 HcmV?d00001 diff --git a/helm/requirements.lock b/helm/requirements.lock new file mode 100644 index 0000000..060f6c9 --- /dev/null +++ b/helm/requirements.lock @@ -0,0 +1,9 @@ +dependencies: +- name: common + repository: http://storage.googleapis.com/kubernetes-charts-incubator + version: 0.0.5 +- name: postgresql + repository: https://kubernetes-charts.storage.googleapis.com + version: 3.13.1 +digest: sha256:e1563a17669e7c46c9db98c4322374903cd88974b24634e0334047f98c2eacc3 +generated: "2019-05-19T08:39:48.617716388+01:00" diff --git a/helm/requirements.yaml b/helm/requirements.yaml new file mode 100644 index 0000000..3bf437d --- /dev/null +++ b/helm/requirements.yaml @@ -0,0 +1,7 @@ +dependencies: + - name: common + repository: http://storage.googleapis.com/kubernetes-charts-incubator + version: 0.0.5 + - name: postgresql + repository: https://kubernetes-charts.storage.googleapis.com + version: 3.13.1 diff --git a/helm/templates/NOTES.txt b/helm/templates/NOTES.txt new file mode 100644 index 0000000..6a10e4a --- /dev/null +++ b/helm/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "mosbot-chart.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "mosbot-chart.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "mosbot-chart.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "mosbot-chart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl new file mode 100644 index 0000000..d662b2b --- /dev/null +++ b/helm/templates/_helpers.tpl @@ -0,0 +1,27 @@ +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "mosbot-chart.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* Generate PostgreSQL database URL */}} +{{- define "mosbot-chart.databaseurl" -}} + postgresql:// + {{- .Values.postgresql.postgresqlUsername -}}: + {{- .Values.postgresql.postgresqlPassword -}}@ + {{- .Release.Name }}-postgresql. + {{- .Release.Namespace -}}/ + {{- .Values.postgresql.postgresqlDatabase -}} +{{- end -}} diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml new file mode 100644 index 0000000..80bfe17 --- /dev/null +++ b/helm/templates/deployment.yaml @@ -0,0 +1,20 @@ +{{- template "common.deployment" (list . "mosbot.deployment") -}} +{{- define "mosbot.deployment" -}} +spec: + replicas: {{ .Values.replicaCount }} + template: + spec: + containers: + - {{ template "common.container" (list . "mosbot.deployment.container") }} +{{- end -}} +{{- define "mosbot.deployment.container" -}} +env: + - name: DATABASE_URL + value: {{ template "mosbot-chart.databaseurl" . }} + {{ if and .Values.dubtrackUsername .Values.dubtrackPassword -}} + - name: DUBTRACK_USERNAME + value: {{ .Values.dubtrackUsername | quote }} + - name: DUBTRACK_PASSWORD + value: {{ .Values.dubtrackPassword | quote }} + {{ end -}} +{{- end -}} diff --git a/helm/values.yaml b/helm/values.yaml new file mode 100644 index 0000000..b442191 --- /dev/null +++ b/helm/values.yaml @@ -0,0 +1,29 @@ +image: + repository: dtgoitia/mosbot + tag: latest + pullPolicy: IfNotPresent + +replicaCount: 1 + +# TODO: setup ingress +service: + type: NodePort + port: 80 + +# Dubtrack credentials +# dubtrackUsername: rococo +# dubtrackPassword: 1234 + +ingress: + enabled: false + tls: false + hosts: + - host: mosbot-chart.local + paths: [] + +postgresql: + postgresqlUsername: dbUser + postgresqlPassword: pass1234 + postgresqlDatabase: myPostgresDatabaseName + service: + port: 5432 diff --git a/setup.py b/setup.py index 2db43af..341cc24 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ ] }, install_requires=[ - 'abot==0.0.1a1.post0.dev23', + 'abot==0.0.1a1.post0.dev30', 'aiopg', 'alembic', 'asyncio-extras',