Corrige permissão do volume de clientes/ via entrypoint, não build
RUN chown no Dockerfile só atinge a imagem: o bind mount de clientes/ substitui o diretório (dono incluído) ao subir o container, apagando qualquer chown feito em build. entrypoint.sh roda como root no início do container, ajusta o dono do volume recém-montado e derruba privilégio para o usuário sd (via gosu) antes do gunicorn. .gitattributes fixa LF em *.sh: autocrlf do Git no Windows senão reescreveria o script para CRLF, quebrando o shebang dentro do container. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
# entrypoint.sh roda dentro do container Linux (gosu/sh) — CRLF quebra a
|
||||||
|
# execução ("no such file or directory", shebang ilegível). Sem esta regra, o
|
||||||
|
# autocrlf=true do Git no Windows reescreve o arquivo na próxima operação que
|
||||||
|
# o toque e o build local passa a falhar mesmo com a imagem correta.
|
||||||
|
*.sh text eol=lf
|
||||||
+18
-4
@@ -23,6 +23,12 @@ ENV PYTHONUNBUFFERED=1 \
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# gosu: o entrypoint precisa iniciar como root (só root faz chown no volume
|
||||||
|
# recém-montado) e depois derrubar privilégio para `sd` antes do gunicorn.
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends gosu \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Dependências em camada própria: mudar código não reinstala pacote.
|
# Dependências em camada própria: mudar código não reinstala pacote.
|
||||||
# requirements.txt é o mesmo do venv Windows; o gunicorn fica separado porque
|
# requirements.txt é o mesmo do venv Windows; o gunicorn fica separado porque
|
||||||
# é só do deploy (no Windows ele não instala).
|
# é só do deploy (no Windows ele não instala).
|
||||||
@@ -33,13 +39,21 @@ RUN pip install --no-cache-dir -r requirements.txt -r requirements-deploy.txt
|
|||||||
COPY scripts/ ./scripts/
|
COPY scripts/ ./scripts/
|
||||||
COPY app/ ./app/
|
COPY app/ ./app/
|
||||||
|
|
||||||
# Usuário sem privilégio. Precisa poder escrever em /app/clientes (o "Salvar
|
# Usuário sem privilégio — quem roda o gunicorn, via entrypoint.sh.
|
||||||
# SD.md") e em /app/_derivados — o dono do volume no host tem de bater com
|
|
||||||
# este UID, ou a gravação recusa com permissão negada.
|
|
||||||
RUN mkdir -p /app/clientes /app/_derivados \
|
RUN mkdir -p /app/clientes /app/_derivados \
|
||||||
&& useradd --create-home --uid 10001 sd \
|
&& useradd --create-home --uid 10001 sd \
|
||||||
&& chown -R sd:sd /app
|
&& chown -R sd:sd /app
|
||||||
USER sd
|
|
||||||
|
# chmod aqui, e não só no arquivo do host: git em Windows não carrega bit de
|
||||||
|
# execução, então sem isso o entrypoint chega ao Coolify sem permissão de
|
||||||
|
# executar.
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
|
# Container começa como root DE PROPÓSITO — é o entrypoint.sh que faz o
|
||||||
|
# chown do volume recém-montado e derruba para `sd` antes do gunicorn. Ver
|
||||||
|
# entrypoint.sh.
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|
||||||
|
|||||||
+5
-3
@@ -5,10 +5,12 @@
|
|||||||
# clientes/ está no .gitignore, então o clone nunca traz esses dados:
|
# clientes/ está no .gitignore, então o clone nunca traz esses dados:
|
||||||
#
|
#
|
||||||
# scp -r clientes/ usuario@vps:/dados/exporta-sd/clientes
|
# scp -r clientes/ usuario@vps:/dados/exporta-sd/clientes
|
||||||
# ssh usuario@vps 'sudo chown -R 10001:10001 /dados/exporta-sd/clientes'
|
|
||||||
#
|
#
|
||||||
# O chown usa o UID do usuário `sd` da imagem. Sem ele, a leitura funciona e o
|
# Não precisa de chown manual: o entrypoint.sh da imagem roda como root no
|
||||||
# "Salvar SD.md" falha com permissão negada — falha parcial, difícil de ler.
|
# início do container e ajusta o dono do volume para o usuário `sd` antes de
|
||||||
|
# derrubar privilégio e subir o gunicorn — ver entrypoint.sh e o ENTRYPOINT
|
||||||
|
# no Dockerfile. (Uma reconsequência: cada `scp` novo devolve os arquivos ao
|
||||||
|
# usuário do ssh no host; some sozinho no próximo restart do container.)
|
||||||
# Depois, no Coolify → Environment Variables, aponte o volume para lá:
|
# Depois, no Coolify → Environment Variables, aponte o volume para lá:
|
||||||
#
|
#
|
||||||
# CLIENTES_DIR=/dados/exporta-sd/clientes
|
# CLIENTES_DIR=/dados/exporta-sd/clientes
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Roda como root no início do container — DEPOIS que os volumes já estão
|
||||||
|
# montados. É por isso que este chown existe aqui e não no Dockerfile: um
|
||||||
|
# RUN chown no build só atinge a imagem, e o bind mount de clientes/ (e de
|
||||||
|
# _derivados/) substitui o diretório — dono incluído — ao subir o container,
|
||||||
|
# apagando qualquer chown feito em tempo de build.
|
||||||
|
#
|
||||||
|
# Sem `|| true` de propósito: se o chown falhar, é melhor a subida quebrar
|
||||||
|
# alto agora do que o "Salvar SD.md" falhar baixo, depois, com permissão
|
||||||
|
# negada.
|
||||||
|
set -e
|
||||||
|
chown -R sd:sd /app/clientes /app/_derivados
|
||||||
|
exec gosu sd "$@"
|
||||||
Reference in New Issue
Block a user