diff --git a/.gitignore b/.gitignore index fc113e4dd..f84d4b89e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ override.env auto-upgrade.log + +# .env files for system (tag, env management) +discovery-provider/.env +creator-node/.env diff --git a/README.md b/README.md index b3ae9abbe..6b52dc612 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,14 @@ Launch audius services via docker compose Actively under development, not recommended for production use. -### Migration from Kubernetes +## Migration from Kubernetes For existing machines running audius services via kube, first run the following commands, ```sh audius-cli auto-upgrade --remove kubectl delete --all-namespaces --all deployments kubectl delete --all-namespaces --all pods +sudo kubeadm reset git clone https://github.com/AudiusProject/audius-docker-compose.git ~/audius-docker-compose cd ~/audius-docker-compose @@ -23,15 +24,13 @@ cat audius-k8s-manifests/config.yaml ``` and set them similarly to before with audius-cli -### Single Click Install +## Single Click Install ```sh bash <(curl https://raw.githubusercontent.com/AudiusProject/audius-docker-compose/main/install.sh) ``` -### Launching an Audius Service - -Currently, this has been tested on Ubuntu 20.04 LTS machines. +## Launching an Audius Service ```sh bash setup.sh @@ -43,6 +42,7 @@ For every key do ```sh audius-cli set-config ``` + #### Creator Node The full list of variables and explanations can be found on the wiki [here](https://github.com/AudiusProject/audius-protocol/wiki/Content-Node:-Configuration-Details#required-environment-variables). @@ -108,6 +108,8 @@ Make sure that your service exposes all the required environment variables. See ### Launch ```sh audius-cli launch -``` -Launch with `--seed-job` for first time discovery provider setup +# Options: +# --seed +# Seeds the database from a snapshot. Required for first-time discovery setup. +``` diff --git a/audius-cli b/audius-cli index bc622af7c..701fef3cf 100755 --- a/audius-cli +++ b/audius-cli @@ -23,9 +23,17 @@ SERVICE_PORTS = { } service_type = click.Choice(["creator-node", "discovery-provider"]) +network_type = click.Choice(["prod", "stage"]) container_type = click.Choice(["backend", "cache", "db"]) +def get_network(ctx, service): + """Returns the network name for the given service.""" + return dotenv.dotenv_values(ctx.obj["manifests_path"] / service / ".env").get( + "NETWORK", "prod" + ) + + @click.group() @click.pass_context def cli(ctx): @@ -41,7 +49,7 @@ def cli(ctx): @click.pass_context def check_config(ctx, service): """Check the config for a service""" - env = ctx.obj["manifests_path"] / service / "env" + env = ctx.obj["manifests_path"] / service / f"{get_network(ctx, service)}.env" override_env = ctx.obj["manifests_path"] / service / "override.env" env_data = dotenv.dotenv_values(env) @@ -122,10 +130,10 @@ def health_check(ctx, service): @cli.command() -@click.option("--seed-job", is_flag=True) @click.argument("service", type=service_type) +@click.option("--seed", is_flag=True) @click.pass_context -def launch(ctx, seed_job, service): +def launch(ctx, service, seed): """Launch the service""" try: ctx.invoke(check_config, service=service) @@ -135,24 +143,24 @@ def launch(ctx, seed_job, service): total_memory = psutil.virtual_memory().total // (1024 ** 3) cpu_count = psutil.cpu_count() - click.echo(f"CPUs:\t{cpu_count}\t(recommended: {RECOMMENDED_CPU_COUNT})") - click.echo(f"Memory:\t{total_memory}GB\t(recommended: {RECOMMENDED_MEMORY}GB)") + click.echo(f"CPUs:\t{cpu_count}\t(required: {RECOMMENDED_CPU_COUNT})") + click.echo(f"Memory:\t{total_memory}GB\t(required: {RECOMMENDED_MEMORY}GB)") if cpu_count < RECOMMENDED_CPU_COUNT or total_memory < RECOMMENDED_MEMORY: - click.secho("System does not meet recommended requirements", fg="red") + click.secho("System does not meet requirements", fg="red") else: - click.secho("System meets recommended requirements", fg="green") + click.secho("System meets requirements", fg="green") click.confirm(click.style("Do you want to continue?", bold=True), abort=True) - if seed_job and service == "discovery-provider": + if seed and service == "discovery-provider": # make sure backend is not running subprocess.run( [ "docker", "compose", "--project-directory", - ctx.obj["manifests_path"] / service, + ctx.obj["manifests_path"] / "discovery-provider", "down", "backend", ], @@ -166,7 +174,7 @@ def launch(ctx, seed_job, service): "--project-directory", ctx.obj["manifests_path"] / "discovery-provider", "run", - "seed-job", + "seed", ], ) @@ -246,11 +254,11 @@ def restart(ctx, service, containers): @cli.command() -@click.option("--unset", is_flag=True) -@click.option("--required", is_flag=True) @click.argument("service", type=service_type) @click.argument("key", required=False) @click.argument("value", required=False) +@click.option("--unset", is_flag=True) +@click.option("--required", is_flag=True) @click.pass_context def set_config(ctx, service, unset, required, key, value): """Set a config value""" @@ -258,7 +266,7 @@ def set_config(ctx, service, unset, required, key, value): click.secho("--required cannot be used when key or value is set", fg="red") sys.exit(1) - env = ctx.obj["manifests_path"] / service / "env" + env = ctx.obj["manifests_path"] / service / f"{get_network(ctx, service)}.env" env_data = dotenv.dotenv_values(env) override_env = ctx.obj["manifests_path"] / service / "override.env" @@ -290,8 +298,8 @@ def set_config(ctx, service, unset, required, key, value): @cli.command() -@click.option("--unset", is_flag=True) @click.argument("tag", required=False) +@click.option("--unset", is_flag=True) @click.pass_context def set_tag(ctx, unset, tag): """Set a config value""" @@ -307,6 +315,24 @@ def set_tag(ctx, unset, tag): dotenv.set_key(env_file, "TAG", tag) +@cli.command() +@click.argument("network", type=network_type, required=False) +@click.option("--unset", is_flag=True) +@click.pass_context +def set_network(ctx, unset, network): + """Set a config value""" + if not unset and network is None: + network = click.prompt(click.style("Network", bold=True)) + + for service in ["creator-node", "discovery-provider"]: + env_file = ctx.obj["manifests_path"] / service / ".env" + + if unset: + dotenv.unset_key(env_file, "NETWORK") + else: + dotenv.set_key(env_file, "NETWORK", network) + + @cli.command() @click.argument("branch", required=False) @click.pass_context @@ -334,8 +360,8 @@ def upgrade(ctx, branch): @cli.command() -@click.option("--remove", is_flag=True) @click.argument("cron-expression", default="0 */6 * * *") +@click.option("--remove", is_flag=True) @click.pass_context def auto_upgrade(ctx, remove, cron_expression): """Setup auto upgrade with a cron job""" diff --git a/creator-node/docker-compose.yml b/creator-node/docker-compose.yml index ea69f55e4..d286585ac 100644 --- a/creator-node/docker-compose.yml +++ b/creator-node/docker-compose.yml @@ -2,6 +2,7 @@ version: "3.9" services: db: + container_name: postgres extends: file: ../common-services.yml service: base-db @@ -11,6 +12,7 @@ services: - creator-node-network cache: + container_name: redis extends: file: ../common-services.yml service: base-cache @@ -18,6 +20,7 @@ services: - creator-node-network backend: + container_name: server image: audius/creator-node:${TAG:-257b60f2ff0b990138d08e618b4e364e3b27b6d7} depends_on: db: @@ -29,7 +32,7 @@ services: ports: - "4000:4000" env_file: - - env + - ${NETWORK}.env - override.env networks: - creator-node-network diff --git a/creator-node/env b/creator-node/prod.env similarity index 100% rename from creator-node/env rename to creator-node/prod.env diff --git a/creator-node/stage.env b/creator-node/stage.env new file mode 100644 index 000000000..cb880d358 --- /dev/null +++ b/creator-node/stage.env @@ -0,0 +1,28 @@ +dbUrl=postgres://postgres:postgres@db:5432/postgres +dbConnectionPoolMax=500 + +redisHost=cache +redisPort=6379 + +dataNetworkId=77 +dataProviderUrl=https://poa-gateway.staging.audius.co +dataRegistryAddress=0x793373aBF96583d5eb71a15d86fFE732CD04D452 +ethNetworkId=3 +ethOwnerWallet=0xcccc7428648c4AdC0ae262D3547584dDAE25c465 +ethProviderUrl=https://eth-ropsten.alchemyapi.io/v2/EEhfbhEFErMbKOp_XQJyvvWKouQjvSss +ethRegistryAddress=0xe39b1cA04fc06c416c4eaBd188Cb1330b8FED781 +ethTokenAddress=0x74f24429ec3708fc21381e017194A5711E93B751 +headersTimeout=60000 +identityService=https://identityservice.staging.audius.co +keepAliveTimeout=5000 +logLevel=info +maxAudioFileSizeBytes=1000000000 +pinAddCIDs=Qma5FGErNqHA32cyEjgp8hnwCFoqyYcBXU1ySKPA6MUJS5,QmYPy9A3zxLeBBuk1vpPNeG5aoMfa5qLNjJgh473Z9zV9b +setTimeout=3600000 +timeout=3600000 + +creatorNodeEndpoint= +delegateOwnerWallet= +delegatePrivateKey= +discoveryProviderWhitelist= +spOwnerWallet= diff --git a/discovery-provider/docker-compose.yml b/discovery-provider/docker-compose.yml index ea7b62706..e0c7b1503 100644 --- a/discovery-provider/docker-compose.yml +++ b/discovery-provider/docker-compose.yml @@ -2,6 +2,7 @@ version: "3.9" services: db: + container_name: postgres extends: file: ../common-services.yml service: base-db @@ -11,6 +12,7 @@ services: - discovery-provider-network cache: + container_name: redis extends: file: ../common-services.yml service: base-cache @@ -18,8 +20,8 @@ services: - discovery-provider-network elasticsearch: - image: docker.elastic.co/elasticsearch/elasticsearch:8.1.0 container_name: elasticsearch + image: docker.elastic.co/elasticsearch/elasticsearch:8.1.0 environment: - network.host=0.0.0.0 - discovery.type=single-node @@ -46,6 +48,7 @@ services: timeout: 5s backend: + container_name: server image: audius/discovery-provider:${TAG:-257b60f2ff0b990138d08e618b4e364e3b27b6d7} depends_on: db: @@ -57,24 +60,26 @@ services: ports: - "5000:5000" env_file: - - env + - ${NETWORK}.env - override.env networks: - discovery-provider-network - seed-job: + seed: image: audius/discovery-provider:${TAG:-257b60f2ff0b990138d08e618b4e364e3b27b6d7} - command: bash -c " curl https://audius-pgdump.s3-us-west-2.amazonaws.com/discProvProduction.dump -O && pg_restore -d $$audius_db_url discProvProduction.dump " + command: bash /usr/share/seed.sh ${NETWORK} env_file: - - env + - ${NETWORK}.env - override.env + volumes: + - ./seed.sh:/usr/share/seed.sh depends_on: - discovery-provider-db: + db: condition: service_healthy networks: - discovery-provider-network profiles: - - seed-job + - seed networks: discovery-provider-network: diff --git a/discovery-provider/env b/discovery-provider/prod.env similarity index 100% rename from discovery-provider/env rename to discovery-provider/prod.env diff --git a/discovery-provider/seed.sh b/discovery-provider/seed.sh new file mode 100644 index 000000000..85b227f0b --- /dev/null +++ b/discovery-provider/seed.sh @@ -0,0 +1,19 @@ +#!/usr/bin/bash +set -e + +NETWORK=$1 + +if [[ "$NETWORK" == "prod" ]]; then + echo "Downloading $NETWORK database..." + curl https://audius-pgdump.s3-us-west-2.amazonaws.com/discProvProduction.dump -O + echo "Restoring $NETWORK database to $audius_db_url..." + pg_restore -d $audius_db_url --clean --if-exists --verbose discProvProduction.dump +elif [[ "$NETWORK" == "stage" ]]; then + echo "Downloading $NETWORK database..." + curl https://audius-pgdump.s3-us-west-2.amazonaws.com/discProvStaging.dump -O + echo "Restoring $NETWORK database to $audius_db_url..." + pg_restore -d $audius_db_url --clean --if-exists --verbose discProvStaging.dump +else + echo "Invalid network: $NETWORK" + exit 1 +fi diff --git a/discovery-provider/stage.env b/discovery-provider/stage.env new file mode 100644 index 000000000..5451506d4 --- /dev/null +++ b/discovery-provider/stage.env @@ -0,0 +1,32 @@ +audius_redis_url=redis://cache:6379/00 + +audius_db_url=postgresql://postgres:postgres@db:5432/postgres +audius_db_url_read_replica=postgresql://postgres:postgres@db:5432/postgres + +audius_contracts_registry=0x793373aBF96583d5eb71a15d86fFE732CD04D452 +audius_cors_allow_all=true +audius_discprov_blacklist_block_processing_window=1200 +audius_discprov_block_processing_window=100 +audius_discprov_env=stage +audius_discprov_identity_service_url=https://identityservice.staging.audius.co +audius_discprov_notifications_max_block_diff=10 +audius_discprov_start_block=0x65a3243860511ed28a933c3a113dea7df368ad53f721cc9d0034c0c75f996afb +audius_discprov_user_metadata_service_url=https://usermetadata.staging.audius.co +audius_eth_contracts_registry=0xe39b1cA04fc06c416c4eaBd188Cb1330b8FED781 +audius_gunicorn_worker_class=eventlet +audius_gunicorn_workers=16 +audius_solana_endpoint=https://audius.rpcpool.com/0b7f8d4970676bd78dbe6fb97e8f +audius_solana_rewards_manager_account=71hWFVYokLaN1PNYzTAWi13EfJ7Xt9VbSWUKsXUT8mxE +audius_solana_rewards_manager_min_slot=0 +audius_solana_rewards_manager_program_address=CDpzvz7DfgbF95jSSCHLX3ERkugyfgn9Fw8ypNZ1hfXp +audius_solana_signer_group_address=DP5ymiCCQurW9jTeDwHAUs3jmfmnqqypGgNF573wje5e +audius_solana_track_listen_count_address=ApR7QbouRviwoE6nLL83omE6GdtM6yUJAsuXw5sPDCQV +audius_solana_user_bank_min_slot=0 +audius_solana_user_bank_program_address=2sjQNmUfkV6yKKi4dPR8gWRgtyma5aiymE3aXL2RAZww +audius_solana_waudio_mint=BELGiMZQ34SDE6x2FUaML2UHDAgBLS64xvhXjX5tBBZo +audius_web3_eth_provider_url=https://eth-ropsten.alchemyapi.io/v2/EEhfbhEFErMbKOp_XQJyvvWKouQjvSss +audius_web3_host=poa-gateway.staging.audius.co +audius_web3_port=443 + +audius_delegate_owner_wallet= +audius_delegate_private_key=