Esta imagem do docker está agora descontinuada. Não há necessidade de usá -lo, você pode usar o Uvicorn com --workers .
Leia mais sobre isso abaixo.
Dockerfilepython3.11 , latest (Dockerfile)python3.10 , (Dockerfile)python3.9 , (Dockerfile)python3.11-slim (Dockerfile)python3.10-slim (Dockerfile)python3.9-slim (Dockerfile) Essas tags não são mais suportadas ou mantidas, elas são removidas do repositório do GitHub, mas as últimas versões pressionadas ainda podem estar disponíveis no Docker Hub se alguém os estiver puxando:
python3.9-alpine3.14python3.8python3.8-slimpython3.8-alpine3.10python3.7python3.7-alpine3.8python3.6python3.6-alpine3.8As tags de última data para essas versões são:
python3.9-alpine3.14-2024-03-11python3.8-2024-11-02python3.8-slim-2024-11-02python3.8-alpine3.10-2024-03-11python3.7-2024-11-02python3.7-alpine3.8-2024-03-11python3.6-2022-11-25python3.6-alpine3.8-2022-11-25 Nota : Existem tags para cada data de construção. Se você precisar "fixar" a versão da imagem do Docker que você usa, poderá selecionar uma dessas tags. Por exemplo, tiangolo/uvicorn-gunicorn:python3.11-2024-11-02 .
Imagem do Docker com Uvicorn gerenciado pela Gunicorn para aplicativos da Web de alto desempenho em Python com ajuste automático de desempenho.
Repo Github : https://github.com/tiangolo/uvicorn-gunicorn-docker
Docker Hub Imagem : https://hub.docker.com/r/tiangolo/uvicorn-gunicorn/
Os aplicativos da Web Python em execução com o Uvicorn (usando a especificação "Asgi" para aplicativos da Web assíncronos Python) mostraram ter algumas das melhores performances, conforme medido por benchmarks de terceiros.
O desempenho alcançável está em pé de igualdade com (e em muitos casos superiores a) GO e Node.js Frameworks.
Esta imagem possui um mecanismo de ajuste automático incluído para iniciar vários processos do trabalhador com base nos núcleos da CPU disponíveis. Dessa forma, você pode simplesmente adicionar seu código e obter alto desempenho automaticamente, o que é útil em implantações simples .
Você provavelmente está usando Kubernetes ou ferramentas semelhantes. Nesse caso, você provavelmente não precisa desta imagem (ou de qualquer outra imagem base semelhante ). É melhor você criar uma imagem do Docker a partir do zero, conforme explicado nos documentos para o FASTAPI em contêineres - Docker: construa uma imagem do Docker para FASTAPI, esse mesmo processo e idéias podem ser aplicados a outras estruturas da ASGI.
Se você possui um conjunto de máquinas com Kubernetes , modo de enxame do Docker, Nomad ou outro sistema complexo semelhante para gerenciar contêineres distribuídos em várias máquinas, provavelmente desejará lidar com a replicação no nível do cluster em vez de usar um gerenciador de processos (como o Gunicorn com trabalhadores de Uvicorn) em cada contêiner, que é o que é a imagem do documento.
Nesses casos (por exemplo, usando Kubernetes), você provavelmente gostaria de criar uma imagem do Docker a partir do zero , instalando suas dependências e executando um único processo uvicorn em vez dessa imagem.
Por exemplo, seu Dockerfile poderia parecer:
FROM python:3.9
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app
CMD [ "uvicorn" , "app.main:app" , "--host" , "0.0.0.0" , "--port" , "80" ]Você pode ler mais sobre isso na documentação do FASTAPI sobre: FASTAPI em contêineres - Docker, pois as mesmas idéias se aplicariam a outras estruturas do ASGI.
Se você definitivamente deseja ter vários trabalhadores em um único contêiner, o Uvicorn agora suporta lidar com subprocessos, incluindo a reinicialização dos mortos. Portanto, não há necessidade de o Gunicorn gerenciar vários trabalhadores em um único contêiner.
Você pode modificar o exemplo Dockerfile de cima, adicionando a opção --workers ao Uvicorn, como:
FROM python:3.9
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app
CMD [ "uvicorn" , "app.main:app" , "--host" , "0.0.0.0" , "--port" , "80" , "--workers" , "4" ]Isso é tudo que você precisa. Você não precisa desta imagem do Docker. ?
Você pode ler mais sobre isso nos documentos FASTAPI sobre a implantação com o Docker.
O Uvicorn não teve apoio para o gerenciamento do processamento dos trabalhadores, incluindo reiniciar trabalhadores mortos. Mas agora sim.
Antes disso, o Gunicorn poderia ser usado como gerente de processos, administrando trabalhadores da UVicorn. Essa complexidade adicionada que não é mais necessária.
O restante deste documento é mantido por razões históricas, mas você provavelmente não precisa dele. ?
tiangolo/uvicorn-gunicornEsta imagem definirá uma configuração sensata com base no servidor em que está em execução (a quantidade de núcleos da CPU disponível) sem fazer sacrifícios.
Possui padrões sensatos, mas você pode configurá -lo com variáveis de ambiente ou substituir os arquivos de configuração.
Há também uma versão fina. Se você quiser um desses, use uma das tags de cima.
Esta imagem foi criada para ser a imagem base para:
Mas poderia ser usado como imagem base para executar qualquer aplicativo da Web Python que use a especificação ASGI.
Se você estiver criando um novo aplicativo da Web Starlette , use o Tiangolo/Uvicorn-Gunicorn-Starlette .
Se você estiver criando um novo aplicativo Web FASTAPI , use o Tiangolo/Uvicorn-Gunicorn-Fastapi .
Nota : O FASTAPI é baseado no Starlette e adiciona vários recursos em cima. Útil para APIs e outros casos: validação de dados, conversão de dados, documentação com openAPI, injeção de dependência, segurança/autenticação e outros.
Nota : A menos que você esteja fazendo algo mais tecnicamente avançado, provavelmente deve estar usando Starlette com Tiangolo/Uvicorn-Gunicorn-Starlette ou FASTAPI com Tiangolo/Uvicorn-Gunicorn-Fastapi .
Você não precisa clonar o repositório do GitHub.
Você pode usar esta imagem como uma imagem base para outras imagens.
Supondo que você tenha um arquivo requirements.txt , você pode ter um Dockerfile como este:
FROM tiangolo/uvicorn-gunicorn:python3.11
COPY ./requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
COPY ./app /app Ele espera um arquivo em /app/app/main.py .
Ou caso contrário, um arquivo em /app/main.py .
E esperará que ele contenha um app variável com seu aplicativo "ASGI".
Em seguida, você pode criar sua imagem a partir do diretório que possui seu Dockerfile , por exemplo:
docker build -t myimage ./docker run -d --name mycontainer -p 80:80 myimageVocê poderá verificá -lo no URL do seu contêiner do Docker, por exemplo: http://192.168.99.100/ ou http://127.0.0.1/ (ou equivalente, usando o host do docker).
Você provavelmente também desejará adicionar dependências para o seu aplicativo e fixá -las a uma versão específica, provavelmente incluindo Uvicorn e Gunicorn.
Dessa forma, você pode garantir que seu aplicativo sempre funcione conforme o esperado.
Você pode instalar pacotes com comandos pip no seu Dockerfile , usando um requirements.txt ou até mesmo usando poesia.
E então você pode atualizar essas dependências de maneira controlada, executando seus testes, certificando -se de que tudo funcione, mas sem quebrar seu aplicativo de produção se alguma nova versão não for compatível.
Aqui está um pequeno exemplo de uma das maneiras pelas quais você pode instalar suas dependências, certificando -se de ter uma versão fixada para cada pacote.
Digamos que você tenha um projeto gerenciado com poesia, então você tem suas dependências de embalagem em um arquivo pyproject.toml . E possivelmente uma poetry.lock de arquivo.lock.
Então você pode ter um Dockerfile usando o Docker Multi-Stage Building com:
FROM python:3.9 as requirements-stage
WORKDIR /tmp
RUN pip install poetry
COPY ./pyproject.toml ./poetry.lock* /tmp/
RUN poetry export -f requirements.txt --output requirements.txt --without-hashes
FROM tiangolo/uvicorn-gunicorn:python3.11
COPY --from=requirements-stage /tmp/requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
COPY ./app /appIsso vai:
./poetry.lock* (terminando com um * ), ele não falhará se esse arquivo ainda não estiver disponível.É importante copiar o código do aplicativo após a instalação das dependências, para que você possa aproveitar o cache do Docker. Dessa forma, ele não terá que instalar tudo a partir do zero sempre que você atualiza seus arquivos de aplicativo, somente quando adicionar novas dependências.
Isso também se aplica a qualquer outra maneira que você use para instalar suas dependências. Se você usar um requirements.txt , copie -o sozinho e instale todas as dependências na parte superior do Dockerfile e adicione seu código de aplicativo após ele.
Essas são as variáveis de ambiente que você pode definir no contêiner para configurá -lo e seus valores padrão:
MODULE_NAMEO "módulo" do Python (arquivo) a ser importado pelo Gunicorn, este módulo conteria o aplicativo real em uma variável.
Por padrão:
app.main se houver um arquivo /app/app/main.py oumain se houver um arquivo /app/main.py Por exemplo, se o seu arquivo principal estivesse em /app/custom_app/custom_main.py , você pode defini -lo como:
docker run -d -p 80:80 -e MODULE_NAME= " custom_app.custom_main " myimageVARIABLE_NAMEA variável dentro do módulo Python que contém o aplicativo ASGI.
Por padrão:
appPor exemplo, se o seu principal arquivo python tiver algo como:
from fastapi import FastAPI
api = FastAPI ()
@ api . get ( "/" )
def read_root ():
return { "message" : "Hello world!" } Nesse caso, api seria a variável com o "aplicativo ASGI". Você pode definir como:
docker run -d -p 80:80 -e VARIABLE_NAME= " api " myimageAPP_MODULEA corda com o módulo Python e o nome da variável passou para o Gunicorn.
Por padrão, configurado com base no variável MODULE_NAME e VARIABLE_NAME :
app.main:app oumain:appVocê pode definir como:
docker run -d -p 80:80 -e APP_MODULE= " custom_app.custom_main:api " myimageGUNICORN_CONFO caminho para um arquivo de configuração do Gunicorn Python.
Por padrão:
/app/gunicorn_conf.py se existir/app/app/gunicorn_conf.py se existir/gunicorn_conf.py (o padrão incluído)Você pode definir como:
docker run -d -p 80:80 -e GUNICORN_CONF= " /app/custom_gunicorn_conf.py " myimageVocê pode usar o arquivo de configuração desta imagem como ponto de partida para o seu.
WORKERS_PER_COREEsta imagem verificará quantos núcleos da CPU estão disponíveis no servidor atual executando seu contêiner.
Ele definirá o número de trabalhadores para o número de núcleos da CPU multiplicados por esse valor.
Por padrão:
1Você pode definir como:
docker run -d -p 80:80 -e WORKERS_PER_CORE= " 3 " myimage Se você usou o valor 3 em um servidor com 2 núcleos de CPU, ele executaria 6 processos de trabalhadores.
Você também pode usar valores de ponto flutuante.
Por exemplo, se você tiver um servidor grande (digamos, com 8 núcleos de CPU) executando vários aplicativos e terá um aplicativo ASGI que você sabe que não precisará de alto desempenho. E você não deseja desperdiçar recursos do servidor. Você pode fazê -lo usar 0.5 trabalhadores por núcleo da CPU. Por exemplo:
docker run -d -p 80:80 -e WORKERS_PER_CORE= " 0.5 " myimageEm um servidor com 8 núcleos de CPU, isso o tornaria iniciado apenas 4 processos de trabalhadores.
NOTA : Por padrão, se WORKERS_PER_CORE for 1 e o servidor tiver apenas 1 núcleo da CPU, em vez de iniciar 1 trabalhador único, ele começará 2. Isso é para evitar um desempenho ruim e o bloqueio de aplicativos (aplicativo do servidor) em pequenas máquinas (máquina de servidor/nuvem/etc). Isso pode ser substituído usando WEB_CONCURRENCY .
MAX_WORKERSDefina o número máximo de trabalhadores para usar.
Você pode usá -lo para permitir que a imagem calcule o número de trabalhadores automaticamente, mas certificando -se de que seja limitado ao máximo.
Isso pode ser útil, por exemplo, se cada trabalhador usar uma conexão de banco de dados e seu banco de dados tiver um limite máximo de conexões abertas.
Por padrão, não está definido, o que significa que é ilimitado.
Você pode definir como:
docker run -d -p 80:80 -e MAX_WORKERS= " 24 " myimageIsso faria a imagem iniciar no máximo 24 trabalhadores, independentemente de quantos núcleos de CPU estão disponíveis no servidor.
WEB_CONCURRENCYSubstituir a definição automática de número de trabalhadores.
Por padrão:
WORKERS_PER_CORE . Portanto, em um servidor com 2 núcleos, por padrão, ele será definido como 2 .Você pode definir como:
docker run -d -p 80:80 -e WEB_CONCURRENCY= " 2 " myimageIsso tornaria a imagem iniciar 2 processos trabalhadores, independentemente de quantos núcleos de CPU estão disponíveis no servidor.
HOSTO "host" usado pelo Gunicorn, o IP onde o Gunicorn ouvirá solicitações.
É o host dentro do contêiner.
Por exemplo, se você definir essa variável para 127.0.0.1 , ela estará disponível apenas dentro do contêiner, não no host que o executa.
É fornecido para a integridade, mas você provavelmente não deve alterá -lo.
Por padrão:
0.0.0.0PORTA porta que o contêiner deve ouvir.
Se você estiver executando seu contêiner em um ambiente restritivo que o obriga a usar alguma porta específica (como 8080 ), poderá defini -lo com essa variável.
Por padrão:
80Você pode definir como:
docker run -d -p 80:8080 -e PORT= " 8080 " myimageBINDO anfitrião e o porto reais passaram para o Gunicorn.
Por padrão, definido com base HOST e PORT variáveis.
Então, se você não mudou nada, ele será definido por padrão como:
0.0.0.0:80Você pode definir como:
docker run -d -p 80:8080 -e BIND= " 0.0.0.0:8080 " myimageLOG_LEVELO nível de log para Gunicorn.
Um de:
debuginfowarningerrorcritical Por padrão, defina como info .
Se você precisar espremer mais desempenho sacrificando o registro, defina -o como warning , por exemplo:
Você pode definir como:
docker run -d -p 80:8080 -e LOG_LEVEL= " warning " myimageWORKER_CLASSA classe a ser usada pelo Gunicorn para os trabalhadores.
Por padrão, defina como uvicorn.workers.UvicornWorker .
O fato de usar o Uvicorn é o que permite usar aplicativos ASGI como FASTAPI e STARLETTE, e é também isso que fornece o desempenho máximo.
Você provavelmente não deveria mudar isso.
Mas se, por algum motivo, você precisar usar o trabalhador uvicorn alternativo: uvicorn.workers.UvicornH11Worker , você pode defini -lo com essa variável de ambiente.
Você pode definir como:
docker run -d -p 80:8080 -e WORKER_CLASS= " uvicorn.workers.UvicornH11Worker " myimageTIMEOUTOs trabalhadores em silêncio por mais do que esses muitos segundos são mortos e reiniciados.
Leia mais sobre isso nos documentos do Gunicorn: Timeout.
Por padrão, definido como 120 .
Observe que as estruturas uvicorn e asgi como FASTAPI e Starlette são assíncronas, não sincronizadas. Portanto, é provavelmente seguro ter um tempo limite mais alto do que para os trabalhadores de sincronização.
Você pode definir como:
docker run -d -p 80:8080 -e TIMEOUT= " 20 " myimageKEEP_ALIVEO número de segundos para aguardar solicitações em uma conexão de manutenção.
Leia mais sobre isso nos documentos de gunicorn: Keepalive.
Por padrão, defina como 2 .
Você pode definir como:
docker run -d -p 80:8080 -e KEEP_ALIVE= " 20 " myimageGRACEFUL_TIMEOUTTempo limite para trabalhadores graciosos reiniciar.
Leia mais sobre isso nos documentos do Gunicorn: Graceful-Timeout.
Por padrão, definido como 120 .
Você pode definir como:
docker run -d -p 80:8080 -e GRACEFUL_TIMEOUT= " 20 " myimageACCESS_LOGO arquivo de log de acesso para gravar.
Por padrão "-" , o que significa stdout (imprimir nos logs do Docker).
Se você deseja desativar ACCESS_LOG , defina -o como um valor vazio.
Por exemplo, você pode desativá -lo com:
docker run -d -p 80:8080 -e ACCESS_LOG= myimageERROR_LOGO arquivo de log de erros para gravar.
Por padrão "-" , o que significa stderr (imprimir nos logs do Docker).
Se você deseja desativar ERROR_LOG , defina -o como um valor vazio.
Por exemplo, você pode desativá -lo com:
docker run -d -p 80:8080 -e ERROR_LOG= myimageGUNICORN_CMD_ARGS Quaisquer configurações adicionais da linha de comando para Gunicorn podem ser passadas na variável de ambiente GUNICORN_CMD_ARGS .
Leia mais sobre isso nos documentos do Gunicorn: Configurações.
Essas configurações terão precedência sobre as outras variáveis de ambiente e qualquer arquivo de configuração do Gunicorn.
Por exemplo, se você tiver um certificado TLS/SSL personalizado que deseja usar, poderá copiá -los para a imagem do Docker ou montá -los no recipiente e definir --keyfile e --certfile para a localização dos arquivos, por exemplo:
docker run -d -p 80:8080 -e GUNICORN_CMD_ARGS= " --keyfile=/secrets/key.pem --certfile=/secrets/cert.pem " -e PORT=443 myimageNota : Em vez de lidar com TLS/SSL e configurá -lo no contêiner, é recomendável usar um "proxy de terminação TLS" como o Traefik. Você pode ler mais sobre isso na documentação do FASTAPI sobre HTTPS.
PRE_START_PATHO caminho onde encontrar o script pré-iniciado.
Por padrão, defina como /app/prestart.sh .
Você pode definir como:
docker run -d -p 80:8080 -e PRE_START_PATH= " /custom/script.sh " myimage A imagem inclui um arquivo de configuração Python padrão do Gunicorn em /gunicorn_conf.py .
Ele usa as variáveis de ambiente declaradas acima para definir todas as configurações.
Você pode substituí -lo incluindo um arquivo em:
/app/gunicorn_conf.py/app/app/gunicorn_conf.py/gunicorn_conf.py/app/prestart.sh Se você precisar executar qualquer coisa antes de iniciar o aplicativo, poderá adicionar um arquivo prestart.sh ao diretório /app . A imagem será detectada e executada automaticamente antes de iniciar tudo.
Por exemplo, se você deseja adicionar migrações SQL Alembic (com sqlalchemy), pode criar um arquivo ./app/prestart.sh no seu diretório de código (que será copiado pelo seu Dockerfile ) com:
#! /usr/bin/env bash
# Let the DB start
sleep 10 ;
# Run migrations
alembic upgrade head E esperaria 10 segundos para dar ao banco de dados algum tempo para iniciar e, em seguida, executar esse comando alembic .
Se você precisar executar um script python antes de iniciar o aplicativo, você pode fazer com que o arquivo /app/prestart.sh execute seu script python, com algo como:
#! /usr/bin/env bash
# Run custom Python script before starting
python /app/my_custom_prestart_script.py Você pode personalizar a localização do script PreStart com a variável de ambiente PRE_START_PATH descrita acima.
O programa padrão que é executado é em /start.sh . Faz tudo descrito acima.
Há também uma versão para o desenvolvimento com relevamento automático ao vivo em:
/start-reload.shPara o desenvolvimento, é útil poder montar o conteúdo do código do aplicativo dentro do contêiner como um "volume do host" do docker, para poder alterar o código e testá -lo ao vivo, sem precisar criar a imagem sempre.
Nesse caso, também é útil executar o servidor com relojo automático ao vivo, para que ele reinicie automaticamente em todas as alterações de código.
O script adicional /start-reload.sh executa o Uvicorn sozinho (sem canhão) e em um único processo.
É ideal para o desenvolvimento.
Por exemplo, em vez de correr:
docker run -d -p 80:80 myimageVocê pode correr:
docker run -d -p 80:80 -v $( pwd ) :/app myimage /start-reload.sh-v $(pwd):/app : significa que o diretório $(pwd) deve ser montado como um volume dentro do contêiner em /app .$(pwd) : executa pwd ("Imprimir diretório de trabalho") e o coloca como parte da string./start-reload.sh : Adicionando algo (como /start-reload.sh ) no final do comando, substitui o "comando" padrão por este. Nesse caso, ele substitui o padrão ( /start.sh ) pela alternativa de desenvolvimento /start-reload.sh . AS /start-reload.sh não é executado com o Gunicorn, nenhuma das configurações que você coloca em um arquivo gunicorn_conf.py não se aplica.
Mas essas variáveis de ambiente funcionarão da mesma forma que descrito acima:
MODULE_NAMEVARIABLE_NAMEAPP_MODULEHOSTPORTLOG_LEVEL Em resumo: você provavelmente não deve usar o Alpine para projetos Python, em vez disso, use as versões slim de imagem do Docker.
Você quer mais detalhes? Continuar lendo?
O Alpine é mais útil para outros idiomas em que você constrói um binário estático em um estágio de imagem de um docker (usando o edifício do Docker de vários estágios) e copie-o para uma imagem alpina simples e, em seguida, execute esse binário. Por exemplo, usando Go.
Mas para o Python, pois a alpina não usa as ferramentas padrão usadas para criar extensões de python, ao instalar pacotes, em muitos casos Python ( pip ) não encontrará um pacote instalável pré -compilado (uma "roda") para alpina. E depois de depurar muitos erros estranhos, você perceberá que precisa instalar muitas ferramentas extras e criar muitas dependências apenas para usar alguns desses pacotes comuns de Python. ?
Isso significa que, embora a imagem alpina original possa ter sido pequena, você acaba com uma imagem com um tamanho comparável ao tamanho que você teria obtido se tivesse acabado de usar uma imagem Python padrão (baseada no Debian) ou em alguns casos ainda maior. ?
E em todos esses casos, levará muito mais tempo para construir, consumindo muito mais recursos, construindo dependências por mais tempo e também aumentando sua pegada de carbono, pois você está usando mais tempo e energia da CPU para cada construção. ?
Se você deseja imagens finas de Python, tente usar as versões slim que ainda são baseadas no Debian, mas são menores. ?
Todas as tags de imagem, configurações, variáveis de ambiente e opções de aplicativos são testadas.
*.pyc com PYTHONDONTWRITEBYTECODE=1 e verifique se os logs são impressos imediatamente com PYTHONUNBUFFERED=1 . Pr #192 por @Estebanx64. EXPOSE as portas 80 e 443 por padrão, pois elas podem ser personalizadas. PR #238 por @tiangolo. --workers . PR #225 por @tiangolo. issue-manager.yml . PR #237 por @tiangolo.latest-changes . PR #236 por @tiangolo.latest-changes.yml . Pr #198 por @alejsdev.arm64 (por exemplo, Mac M1). Pr #195 por @tiangolo. README.md . Pr #197 por @alejsdev. Os destaques deste lançamento são:
python3.6-2022-11-25 .slim . PR #40.WORKER_CLASSTIMEOUTKEEP_ALIVEGRACEFUL_TIMEOUTACCESS_LOGERROR_LOGGUNICORN_CMD_ARGSMAX_WORKERSpip durante a instalação com --no-cache-dir . Pr #13 por @pmav99.PRE_START_PATH Env var. PR #30.PRE_START_PATH ENV var. Pr #12 por @mgfinch.tiangolo/uvicorn-gunicorn:python3.7-2019-10-15 . PR #15./dev/shm para melhorar o desempenho. PR #9 por @wshayes./start-reload.sh , verifique a documentação atualizada. Pr #6.WORKERS_PER_CORE Por padrão para 1 , pois mostra ter o melhor desempenho nos benchmarks.WEB_CONCURRENCY não estiver definido, para um mínimo de 2 trabalhadores. Isso é para evitar o mau desempenho e o bloqueio de aplicativos (aplicativo do servidor) em pequenas máquinas (máquina de servidor/nuvem/etc). Isso pode ser substituído usando WEB_CONCURRENCY . Isso se aplica, por exemplo, no caso em que WORKERS_PER_CORE estão definidos como 1 (o padrão) e o servidor possui apenas 1 núcleo da CPU. Pr #5./start.sh execute de forma independente, lendo e gerando variáveis de ambiente padrão usadas. E remova /entrypoint.sh pois não modifica nada no sistema, lê apenas variáveis de ambiente. Pr #4./app/prestart.sh . Este projeto está licenciado nos termos da licença do MIT.