mirror of
https://github.com/Eugeny/tabby-web.git
synced 2025-06-08 05:29:52 +00:00
a unified docker image
This commit is contained in:
parent
e1b0d01ac3
commit
34ac0781c2
49
.github/workflows/docker.yml
vendored
Normal file
49
.github/workflows/docker.yml
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
name: Docker
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '25 12 * * *'
|
||||
push:
|
||||
branches: [ master ]
|
||||
# Publish semver tags as releases.
|
||||
tags: [ 'v*.*.*' ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: eugeny/tabby-web
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
|
||||
with:
|
||||
build-args: EXTRA_DEPS=gcsfs
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
56
Dockerfile
Normal file
56
Dockerfile
Normal file
@ -0,0 +1,56 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM node:12-alpine AS frontend-build
|
||||
WORKDIR /app
|
||||
COPY frontend/package.json frontend/yarn.lock ./
|
||||
RUN yarn
|
||||
COPY frontend/webpack* frontend/tsconfig.json ./
|
||||
COPY frontend/assets assets
|
||||
COPY frontend/src src
|
||||
COPY frontend/theme theme
|
||||
RUN yarn run build
|
||||
RUN yarn run build:server
|
||||
|
||||
FROM node:12-alpine AS frontend
|
||||
WORKDIR /app
|
||||
COPY --from=frontend-build /app/build build
|
||||
COPY --from=frontend-build /app/build-server build-server
|
||||
COPY frontend/package.json .
|
||||
|
||||
CMD ["npm", "start"]
|
||||
|
||||
# ----
|
||||
|
||||
FROM python:3.7-alpine AS build-backend
|
||||
ARG EXTRA_DEPS
|
||||
|
||||
RUN apk add build-base musl-dev libffi-dev openssl-dev mariadb-dev
|
||||
|
||||
WORKDIR /app
|
||||
RUN pip install -U setuptools 'cryptography>=3.0,<3.1' poetry==1.1.7
|
||||
COPY backend/pyproject.toml backend/poetry.lock ./
|
||||
RUN poetry config virtualenvs.path /venv
|
||||
RUN poetry install --no-dev --no-ansi --no-interaction
|
||||
RUN poetry run pip install -U setuptools $EXTRA_DEPS
|
||||
|
||||
COPY backend/manage.py backend/gunicorn.conf.py ./
|
||||
COPY backend/tabby tabby
|
||||
COPY --from=frontend /app/build /frontend
|
||||
|
||||
ARG BUNDLED_TABBY=1.0.163
|
||||
|
||||
RUN FRONTEND_BUILD_DIR=/frontend /venv/*/bin/python ./manage.py collectstatic --noinput
|
||||
RUN FRONTEND_BUILD_DIR=/frontend /venv/*/bin/python ./manage.py add_version ${BUNDLED_TABBY}
|
||||
|
||||
FROM python:3.7-alpine AS backend
|
||||
|
||||
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.9.0/wait /wait
|
||||
RUN chmod +x /wait
|
||||
|
||||
RUN apk add mariadb-connector-c
|
||||
|
||||
COPY --from=build-backend /app /app
|
||||
COPY --from=build-backend /venv /venv
|
||||
|
||||
COPY backend/start.sh backend/manage.sh /
|
||||
RUN chmod +x /start.sh /manage.sh
|
||||
CMD ["/start.sh"]
|
25
README.md
25
README.md
@ -16,27 +16,30 @@ Tabby Web serves the [Tabby Terminal](https://github.com/Eugeny/tabby) as a web
|
||||
* A database server supported by Django (MariaDB, Postgres, SQLite, etc.)
|
||||
* Storage for distribution files - local, S3, GCS or others supported by `fsspec`
|
||||
|
||||
# Using Docker images
|
||||
# Quickstart (using `docker-compose`)
|
||||
|
||||
Tabby Web consists of two Docker images - `backend` and `frontend`. See an example set up in `docker-compose.yml`
|
||||
You'll need:
|
||||
|
||||
* OAuth credentials from GitHub, GitLab, Google or Microsoft for authentication.
|
||||
* For SSH and Telnet: a [`tabby-connection-gateway`](https://github.com/Eugeny/tabby-connection-gateway) to forward traffic.
|
||||
|
||||
```bash
|
||||
docker-compose up -e SOCIAL_AUTH_GITHUB_KEY=xxx -e SOCIAL_AUTH_GITHUB_SECRET=yyy
|
||||
```
|
||||
|
||||
will start Tabby Web on port 9090 with MariaDB as a storage backend.
|
||||
|
||||
For SSH and Telnet, once logged in, enter your connection gateway address and auth token in the settings.
|
||||
|
||||
## Environment variables
|
||||
|
||||
### Frontend
|
||||
|
||||
* `BACKEND_URL` (required if running the backend in a separate Docker container).
|
||||
* `WEB_CONCURRENCY`
|
||||
|
||||
### Backend
|
||||
|
||||
* `DATABASE_URL` (required).
|
||||
* `FRONTEND_URL`
|
||||
* `APP_DIST_STORAGE`: a `file://`, `s3://`, or `gcs://` URL to store app distros in.
|
||||
* `SOCIAL_AUTH_*_KEY` & `SOCIAL_AUTH_*_SECRET`: social login credentials, supported providers are `GITHUB`, `GITLAB`, `MICROSOFT_GRAPH` and `GOOGLE_OAUTH2`.
|
||||
|
||||
## Adding Tabby app versions
|
||||
|
||||
* `docker-compose run backend ./manage.py add_version 1.0.156-nightly.2`
|
||||
* `docker-compose run tabby /manage.sh add_version 1.0.163`
|
||||
|
||||
# Development setup
|
||||
|
||||
|
@ -1 +1,2 @@
|
||||
__pycache__
|
||||
public
|
||||
|
4
backend/manage.sh
Normal file
4
backend/manage.sh
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
/wait
|
||||
cd /app
|
||||
/venv/*/bin/python ./manage.py $@
|
@ -1,4 +1,5 @@
|
||||
#!/bin/sh
|
||||
/wait
|
||||
cd /app
|
||||
./manage.py migrate
|
||||
gunicorn
|
||||
/venv/*/bin/python ./manage.py migrate
|
||||
/venv/*/bin/gunicorn
|
||||
|
@ -42,7 +42,7 @@ class ChooseGatewayViewSet(RetrieveModelMixin, GenericViewSet):
|
||||
gateways = list(self.queryset)
|
||||
random.shuffle(gateways)
|
||||
if not len(gateways):
|
||||
raise NotFound()
|
||||
raise NoGatewaysError()
|
||||
|
||||
loop = asyncio.new_event_loop()
|
||||
try:
|
||||
|
@ -12,12 +12,12 @@ class IndexView(APIView):
|
||||
def get(self, request, format=None):
|
||||
if settings.FRONTEND_URL:
|
||||
return HttpResponseRedirect(settings.FRONTEND_URL)
|
||||
return static.serve(request, 'index.html', document_root=str(settings.FRONTEND_BUILD_DIR))
|
||||
return static.serve(request, 'index.html', document_root=str(settings.STATIC_ROOT))
|
||||
|
||||
|
||||
class TerminalView(APIView):
|
||||
def get(self, request, format=None):
|
||||
response = static.serve(request, 'terminal.html', document_root=str(settings.FRONTEND_BUILD_DIR))
|
||||
response = static.serve(request, 'terminal.html', document_root=str(settings.STATIC_ROOT))
|
||||
response['X-Frame-Options'] = 'SAMEORIGIN'
|
||||
return response
|
||||
|
||||
|
@ -9,8 +9,6 @@ load_dotenv()
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
FRONTEND_BUILD_DIR = BASE_DIR / '../frontend/build'
|
||||
|
||||
SECRET_KEY = os.getenv('DJANGO_SECRET_KEY', 'django-insecure')
|
||||
DEBUG = bool(os.getenv('DEBUG', False))
|
||||
|
||||
@ -135,11 +133,6 @@ LOGGING = {
|
||||
},
|
||||
}
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
if FRONTEND_BUILD_DIR.exists():
|
||||
STATICFILES_DIRS = [FRONTEND_BUILD_DIR]
|
||||
STATIC_ROOT = BASE_DIR / 'public'
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
CSRF_USE_SESSIONS = False
|
||||
@ -172,6 +165,7 @@ SOCIAL_AUTH_PIPELINE = (
|
||||
|
||||
APP_DIST_STORAGE = os.getenv('APP_DIST_STORAGE', 'file://' + str(BASE_DIR / 'app-dist'))
|
||||
NPM_REGISTRY = os.getenv('NPM_REGISTRY', 'https://registry.npmjs.org').rstrip('/')
|
||||
FRONTEND_BUILD_DIR = Path(os.getenv('FRONTEND_BUILD_DIR', BASE_DIR / '../frontend/build'))
|
||||
|
||||
FRONTEND_URL = None
|
||||
BACKEND_URL = None
|
||||
@ -229,6 +223,12 @@ else:
|
||||
GITHUB_ELIGIBLE_SPONSORSHIPS = []
|
||||
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
if FRONTEND_BUILD_DIR.exists():
|
||||
STATICFILES_DIRS = [FRONTEND_BUILD_DIR]
|
||||
STATIC_ROOT = BASE_DIR / 'public'
|
||||
|
||||
|
||||
if FRONTEND_URL:
|
||||
CORS_ALLOWED_ORIGINS = [FRONTEND_URL]
|
||||
CORS_ALLOW_CREDENTIALS = True
|
||||
|
21
docker-compose.split.yml
Normal file
21
docker-compose.split.yml
Normal file
@ -0,0 +1,21 @@
|
||||
services:
|
||||
frontend:
|
||||
build: frontend
|
||||
ports:
|
||||
- 9090:80
|
||||
environment:
|
||||
- PORT=80
|
||||
- BACKEND_URL=http://localhost:9091
|
||||
backend:
|
||||
build: backend
|
||||
ports:
|
||||
- 9091:80
|
||||
volumes:
|
||||
- ./app-dist:/app-dist
|
||||
environment:
|
||||
- DATABASE_URL
|
||||
- PORT=80
|
||||
- FRONTEND_URL=http://localhost:9090
|
||||
- ENABLE_HOMEPAGE=False
|
||||
- DEBUG=False
|
||||
- APP_DIST_STORAGE=file:///app-dist
|
@ -1,21 +1,26 @@
|
||||
services:
|
||||
frontend:
|
||||
build: frontend
|
||||
tabby:
|
||||
build: .
|
||||
restart: always
|
||||
depends_on:
|
||||
- db
|
||||
ports:
|
||||
- 9090:80
|
||||
environment:
|
||||
- PORT=80
|
||||
- BACKEND_URL=http://localhost:9091
|
||||
backend:
|
||||
build: backend
|
||||
ports:
|
||||
- 9091:80
|
||||
volumes:
|
||||
- ./app-dist:/app-dist
|
||||
environment:
|
||||
- DATABASE_URL
|
||||
- DATABASE_URL=mysql://root:123@db/tabby
|
||||
- PORT=80
|
||||
- FRONTEND_URL=http://localhost:9090
|
||||
- ENABLE_HOMEPAGE=False
|
||||
- DEBUG=False
|
||||
- APP_DIST_STORAGE=file:///app-dist
|
||||
- WAIT_HOSTS=db:3306
|
||||
|
||||
db:
|
||||
image: mariadb:10.7.1
|
||||
restart: always
|
||||
environment:
|
||||
MARIADB_DATABASE: tabby
|
||||
MARIADB_USER: user
|
||||
MARIADB_PASSWORD: 123
|
||||
MYSQL_ROOT_PASSWORD: 123
|
||||
|
Loading…
x
Reference in New Issue
Block a user