mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-08 21:18:12 +08:00
* early, non-working eb config * hosted cellxgene In this PR, contains scripts and instructions for deploying cellxgene for AWS elastic beanstalk. It supports the multi-dataset option. The Makefile in the server/eb directory creates an artifact.zip file, which can be deploy at AWS EB. The server/eb directory contains: app.py - flask app to run the server Makefile - which creates an artifact.zip file which can be deployed. README.md - instructions for setting up and deploying the eb app. * hosted cellxgene (#38) In this PR, contains scripts and instructions for deploying cellxgene for AWS elastic beanstalk. It supports the multi-dataset option. The Makefile in the server/eb directory creates an artifact.zip file, which can be deploy at AWS EB. The server/eb directory contains: app.py - flask app to run the server Makefile - which creates an artifact.zip file which can be deployed. README.md - instructions for setting up and deploying the eb app. * Update how artifact.zip is created prune the server/test and server/eb directories * Remove debugging print statements * fixes from review comments * fix lint Co-authored-by: bkmartinjr <bruce@chanzuckerberg.com>
This commit is contained in:
co-authored by
bkmartinjr
parent
bdd69160e2
commit
b3e9719602
@@ -34,25 +34,13 @@ build-client:
|
|||||||
build-cli: build-client
|
build-cli: build-client
|
||||||
git ls-files server/ | cpio -pdm $(BUILDDIR)
|
git ls-files server/ | cpio -pdm $(BUILDDIR)
|
||||||
cp -r client/build/ $(CLIENTBUILD)
|
cp -r client/build/ $(CLIENTBUILD)
|
||||||
mkdir -p $(SERVERBUILD)/common/web/static/img
|
$(call copy_client_assets,$(CLIENTBUILD),$(SERVERBUILD))
|
||||||
mkdir -p $(SERVERBUILD)/common/web/templates/
|
|
||||||
cp $(CLIENTBUILD)/index.html $(SERVERBUILD)/common/web/templates/
|
|
||||||
cp -r $(CLIENTBUILD)/static $(SERVERBUILD)/common/web/
|
|
||||||
cp $(CLIENTBUILD)/favicon.png $(SERVERBUILD)/common/web/static/img
|
|
||||||
cp $(CLIENTBUILD)/service-worker.js $(SERVERBUILD)/common/web/static/js/
|
|
||||||
cp MANIFEST.in README.md setup.cfg setup.py $(BUILDDIR)
|
cp MANIFEST.in README.md setup.cfg setup.py $(BUILDDIR)
|
||||||
|
|
||||||
# If you are actively developing in the server folder use this, dirties the source tree
|
# If you are actively developing in the server folder use this, dirties the source tree
|
||||||
.PHONY: build-for-server-dev
|
.PHONY: build-for-server-dev
|
||||||
build-for-server-dev: clean-server build-client
|
build-for-server-dev: clean-server build-client
|
||||||
mkdir -p server/common/web/static/img
|
$(call copy_client_assets,client/build,server)
|
||||||
mkdir -p server/common/web/static/js
|
|
||||||
mkdir -p server/common/web/templates/
|
|
||||||
cp client/build/index.html server/common/web/templates/
|
|
||||||
cp -r client/build/static server/common/web/
|
|
||||||
cp client/build/favicon.png server/common/web/static/img
|
|
||||||
cp client/build/service-worker.js server/common/web/static/js/
|
|
||||||
|
|
||||||
|
|
||||||
# TESTING
|
# TESTING
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
|
|||||||
@@ -17,3 +17,17 @@ export JEST_ENV := $(call get_or_else_dev_env_default,JEST_ENV)
|
|||||||
export CXG_SERVER_PORT
|
export CXG_SERVER_PORT
|
||||||
export CXG_CLIENT_PORT
|
export CXG_CLIENT_PORT
|
||||||
export JEST_ENV
|
export JEST_ENV
|
||||||
|
|
||||||
|
# copy the client assests to a location known to the server
|
||||||
|
# $(1) is the source of the client assets
|
||||||
|
# $(2) is the destination
|
||||||
|
define copy_client_assets
|
||||||
|
mkdir -p $(2)/common/web/static/img
|
||||||
|
mkdir -p $(2)/common/web/static/js
|
||||||
|
mkdir -p $(2)/common/web/templates/
|
||||||
|
cp $(1)/index.html $(2)/common/web/templates/
|
||||||
|
cp -r $(1)/static $(2)/common/web/
|
||||||
|
cp $(1)/favicon.png $(2)/common/web/static/img
|
||||||
|
cp $(1)/service-worker.js $(2)/common/web/static/js/
|
||||||
|
endef
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class AppConfig(object):
|
|||||||
self.title = ""
|
self.title = ""
|
||||||
self.about = None
|
self.about = None
|
||||||
self.scripts = []
|
self.scripts = []
|
||||||
self.layout = None
|
self.layout = []
|
||||||
self.max_category_items = 100
|
self.max_category_items = 100
|
||||||
self.diffexp_lfc_cutoff = 0.01
|
self.diffexp_lfc_cutoff = 0.01
|
||||||
self.disable_diffexp = False
|
self.disable_diffexp = False
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
files:
|
||||||
|
"/etc/httpd/conf.d/enable_mod_deflate.conf":
|
||||||
|
mode: "000644"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
content: |
|
||||||
|
<IfModule mod_deflate.c>
|
||||||
|
|
||||||
|
AddOutputFilterByType DEFLATE text/plain
|
||||||
|
AddOutputFilterByType DEFLATE text/html
|
||||||
|
AddOutputFilterByType DEFLATE application/xhtml+xml
|
||||||
|
AddOutputFilterByType DEFLATE text/xml
|
||||||
|
AddOutputFilterByType DEFLATE application/xml
|
||||||
|
AddOutputFilterByType DEFLATE application/xml+rss
|
||||||
|
AddOutputFilterByType DEFLATE application/x-javascript
|
||||||
|
AddOutputFilterByType DEFLATE text/javascript
|
||||||
|
AddOutputFilterByType DEFLATE text/css
|
||||||
|
AddOutputFilterByType DEFLATE application/octet-stream
|
||||||
|
|
||||||
|
DeflateCompressionLevel 9
|
||||||
|
|
||||||
|
BrowserMatch ^Mozilla/4 gzip-only-text/html
|
||||||
|
BrowserMatch ^Mozilla/4\.0[678] no-gzip
|
||||||
|
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
|
||||||
|
|
||||||
|
<IfModule mod_headers.c>
|
||||||
|
Header append Vary User-Agent env=!dont-vary
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# Configue WSGI so that it will work with numpy, scanpy, etc, which all use the
|
||||||
|
# Python SWIG, and therefore will deadlock on start. For more information, see
|
||||||
|
# https://modwsgi.readthedocs.io/en/develop/user-guides/application-issues.html#python-simplified-gil-state-api
|
||||||
|
files:
|
||||||
|
"/etc/httpd/conf.d/wsgi_custom.conf":
|
||||||
|
mode: "000644"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
content: |
|
||||||
|
WSGIApplicationGroup %{GLOBAL}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
include ../../common.mk
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f artifact.zip
|
||||||
|
rm -rf artifact.dir
|
||||||
|
|
||||||
|
|
||||||
|
# Build the ElasticBeanstalk configuration and deployment bundle,
|
||||||
|
# such that deployment can be done with a simple `eb deploy`.
|
||||||
|
# Presumes that a top-level `make build-client` has been done to
|
||||||
|
# create the client static assets.
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build: clean
|
||||||
|
mkdir artifact.dir; \
|
||||||
|
(cd ../.. ; \
|
||||||
|
git ls-files server/ | cpio -pdm server/eb/artifact.dir ; ); \
|
||||||
|
$(call copy_client_assets,../../client/build,artifact.dir/server) ; \
|
||||||
|
cp app.py artifact.dir/application.py; \
|
||||||
|
cp ../requirements.txt artifact.dir; \
|
||||||
|
cp -r .ebextensions artifact.dir; \
|
||||||
|
(cd artifact.dir; zip -r ../artifact.zip . --exclude server/test/\* server/eb/\* ); \
|
||||||
|
if ! grep artifact.zip .elasticbeanstalk/config.yml ; then \
|
||||||
|
mkdir -p .elasticbeanstalk ; cat config_deploy.yaml >> .elasticbeanstalk/config.yml ; fi
|
||||||
|
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# AWS Elastic Beanstalk
|
||||||
|
|
||||||
|
This directory contains script to aid in creating and deploying cellxgene on
|
||||||
|
an AWS Elastic Beanstalk instance.
|
||||||
|
|
||||||
|
This will result in a variant of cellxgene, running on AWS EC2 instances, serving data from S3.
|
||||||
|
All datasets must be in the new CXG (tiledb) format - see the converter script cxgtool.py
|
||||||
|
in server/converters - and located in a single S3 prefix, which is accessible to the instance.
|
||||||
|
In the current incarnation, no access control or authentication support is available
|
||||||
|
(outside of anything you configure yourself), so this is most appropriate for public datasets.
|
||||||
|
|
||||||
|
This is early development work, and will change significantly in the near future.
|
||||||
|
We would love feedback on it, but please assume it will change.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. Some familiarity with AWS EB, S3, and IAM are needed.
|
||||||
|
|
||||||
|
2. Install the awsebcli.
|
||||||
|
Instruction are here:
|
||||||
|
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-install.html
|
||||||
|
|
||||||
|
3. In the top level directory, run ```make build-client``` to create the client static assets.
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
These steps are meant to serve as an example.
|
||||||
|
There are many more options to these commands that may be important or necessary for your environment.
|
||||||
|
|
||||||
|
1. Create an S3 bucket
|
||||||
|
|
||||||
|
Upload your matrix files to this bucket
|
||||||
|
|
||||||
|
2. Create an elastic beanstalk application. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
EB_APP=cellxgene-app
|
||||||
|
eb init -p python-3.6 $EB_APP
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Create the artifact.zip file for the application
|
||||||
|
|
||||||
|
```
|
||||||
|
make build
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Create an environment
|
||||||
|
|
||||||
|
```
|
||||||
|
# name of the environment
|
||||||
|
EB_ENV=cellxgene-env
|
||||||
|
# type of ec2 instance to run the cellxgene server.
|
||||||
|
EB_INSTANCE=m5.large
|
||||||
|
CXG_DATAROOT=<location to your S3 bucket>
|
||||||
|
|
||||||
|
eb create $EB_ENV --instance-type $EB_INSTANCE --envvars CXG_DATAROOT=$CXG_DATAROOT
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Give the elastic beanstalk environment access to the S3 bucket.
|
||||||
|
|
||||||
|
This link may provide some useful information:
|
||||||
|
https://aws.amazon.com/premiumsupport/knowledge-center/elastic-beanstalk-s3-bucket-instance/
|
||||||
|
|
||||||
|
6. Deploy the application
|
||||||
|
|
||||||
|
```
|
||||||
|
eb deploy $EB_ENV
|
||||||
|
```
|
||||||
|
|
||||||
|
7. Open the application in a browser
|
||||||
|
|
||||||
|
```
|
||||||
|
eb open
|
||||||
|
```
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
"""cellxgene AWS elastic beanstalk application"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
if os.path.isdir("/opt/python/log"):
|
||||||
|
# This is the standard location where Amazon EC2 instances store the application logs.
|
||||||
|
logging.basicConfig(
|
||||||
|
filename="/opt/python/log/app.log",
|
||||||
|
level=logging.DEBUG,
|
||||||
|
format="%(asctime)s.%(msecs)03d %(levelname)s %(module)s - %(funcName)s: %(message)s",
|
||||||
|
datefmt="%Y-%m-%d %H:%M:%S",
|
||||||
|
)
|
||||||
|
|
||||||
|
# echo the logs to stdout. Useful for local testing
|
||||||
|
logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
|
||||||
|
|
||||||
|
SERVERDIR = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
sys.path.append(SERVERDIR)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from server.common.app_config import AppConfig
|
||||||
|
from server.app.app import Server
|
||||||
|
from server.data_common.matrix_loader import MatrixDataCacheManager
|
||||||
|
except Exception:
|
||||||
|
logging.exception("Exception importing server modules")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
dataroot = os.getenv("CXG_DATAROOT")
|
||||||
|
if dataroot is None:
|
||||||
|
logging.error("CXG_DATAROOT environment variable must be set")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
app_config = AppConfig(
|
||||||
|
datapath=None,
|
||||||
|
dataroot=dataroot,
|
||||||
|
title="",
|
||||||
|
about=None,
|
||||||
|
scripts=[],
|
||||||
|
layout=[],
|
||||||
|
max_category_items=100,
|
||||||
|
diffexp_lfc_cutoff=0.01,
|
||||||
|
obs_names=None,
|
||||||
|
var_names=None,
|
||||||
|
anndata_backed=False,
|
||||||
|
disable_diffexp=False)
|
||||||
|
|
||||||
|
matrix_data_cache_manager = MatrixDataCacheManager()
|
||||||
|
annotations = None
|
||||||
|
|
||||||
|
server = Server(matrix_data_cache_manager, annotations, app_config)
|
||||||
|
|
||||||
|
debug = False
|
||||||
|
application = server.app
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
logging.exception("Caught exception during initialization")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logging.info(f"starting server with CXG_DATAROOT={dataroot}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
application.run(debug=debug, threaded=not debug, use_debugger=False)
|
||||||
|
except Exception:
|
||||||
|
logging.exception("Caught exception during server run")
|
||||||
|
sys.exit(1)
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
deploy:
|
||||||
|
artifact: artifact.zip
|
||||||
Reference in New Issue
Block a user