I'm having some trouble setting up a Nuxt and Rails container using Docker. The two containers are separate, but interact with each other.
Currently, I'm having trouble running the dev servers for both the Nuxt and the Rails containers due to insufficient permissions. Looking at the logs for both of the containers, it seems that Docker can't do actions such as mkdir.
EACCESS: Permission Denied: 'mkdir: /usr/src/app/.nuxt' # nuxt
EACCESS: Permission Denied: 'mkdir: /usr/src/app/tmp' # rails
My docker-compose.dev.yml file
version: 3
services:
backend:
privileged: true
image: tablevibes-backend
build:
dockerfile: Dockerfile-dev
context: tablevibes-backend
args:
UID: ${UID:-1001}
BUNDLER_VERSION: 2.0.2
PG_MAJOR: 10
mode: development
tty: true
stdin_open: true
volumes:
- ./tablevibes-backend:/usr/src/app:Z
- gem_data_api:/usr/local/bundle:cached
ports:
- "3000:3000"
depends_on:
- db
user: rails
client-ui:
image: client-ui
command: yarn run dev
build:
context: client-ui
dockerfile: Dockerfile-dev
args:
UID: ${UID:-1001}
PORT: 5000
MODE: DEV
restart: always
volumes:
- ./client-ui:/usr/src/app
- client_ui_node_modules:/usr/src/app/node_modules:cached
ports:
- 5000:5000
user: client-ui
The 2 Dockerfiles
The Rails Dockerfile-dev
FROM ruby:2.6.3
ARG PG_MAJOR
ARG BUNDLER_VERSION
ARG UID
ARG MODE
RUN adduser rails --uid $UID --disabled-password --gecos ""
# Add POSTGRESQL to the source list using the right version
RUN curl -sSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
&& echo 'deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main' $PG_MAJOR > /etc/apt/sources.list.d/pgdg.list
ENV RAILS_ENV $MODE
RUN apt-get update -qq && apt-get install -y postgresql-client-$PG_MAJOR vim
RUN apt-get -y install sudo
WORKDIR /usr/src/app
CMD chown -R rails /usr/src/app
COPY Gemfile /usr/src/app/Gemfile
COPY Gemfile.lock /usr/src/app/Gemfile.lock
ENV BUNDLER_VERSION $BUNDLER_VERSION
RUN gem install bundler:$BUNDLER_VERSION
RUN bundle install
COPY . /usr/src/app
# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
The Nuxt Dockerfile-dev
FROM node:10
ARG UID
ARG MODE=DEV
ARG PORT
RUN adduser client-ui --uid $UID --disabled-password --gecos ""
RUN apt-get update
RUN apt-get -y install sudo
RUN mkdir /usr/src/app
RUN chown -R client-ui /usr/src/app
COPY package.json yarn.lock /usr/src/app
RUN yarn install
COPY . /usr/src/app
ENV API_URL=http://localhost:3000/v1
ENV REVIEW_URL=http://localhost:8000
# expose 5000 on container
EXPOSE $PORT
# set app serving to permissive / assigned
ENV NUXT_HOST=0.0.0.0
# set app port
ENV NUXT_PORT=$PORT
My problem is that those lines where I do RUN chown ... never seem to take place. If I manually go into the containers with docker exec -u root -it backend bash and run chown -R rails . manually, everything works as expected. Likewise I tried running chmod 777 as a test, however that also had no effect on the permission denied error I keep getting.
What might be causing Docker to ignore my chown command?
This Stack Overflow question seems relevant, however it doesn't quite apply because I don't have any VOLUME mounts inside my Dockerfiles. A user in the comments of the accepted answer has my same issue, though unfortunately no solution.
Containers are like ogres, or onions, they have layers.
When using VOLUMEs or MOUNTs, the directory (or file) is not actually IN the container, but only appears to be in it.
Your Dockerfile uses a layer for /usr/src/app, which as you probably already know is your ./tablevibes-backend directory on your host computer.
services:
backend:
volumes:
- ./tablevibes-backend:/usr/src/app:Z
When you use a volume or mount in this way, the only thing Docker can do is simple CRUD (create, read, update, delete) options, it can not (and should not) modify the metadata as it is modifying your host drive, which could be a security issue.
try this:
sudo chown -R $USER:$USER .
Related
I'm trying to set up a Profittrailer Docker container through Docker Compose.
I've tested the Docker image using docker run which launches the container just fine.
When using docker-compose up instead, PM2 (NodeJS process manager) fails to find the configuration file. I believe this happens because the container is unable to write to the shared volume.
Below is my Dockerfile:
FROM eclipse-temurin:8-jdk-alpine
ARG PT_VERSION=2.5.32
ENV PT_VERSION ${PT_VERSION}
RUN mkdir -p /app/
# install tools
RUN apk update && apk add unzip curl
# install nodejs
RUN apk add --update nodejs npm
RUN npm install pm2#latest -g
# install profittrailer
RUN curl https://github.com/taniman/profit-trailer/releases/download/$PT_VERSION/ProfitTrailer-$PT_VERSION.zip -L -o /app/profittrailer.zip
RUN unzip /app/profittrailer.zip -d /app/ && mv /app/ProfitTrailer-$PT_VERSION /app/ProfitTrailer
WORKDIR /app/ProfitTrailer
RUN chmod +x ProfitTrailer.jar
VOLUME /app/ProfitTrailer
CMD pm2 start pm2-ProfitTrailer.json && pm2 log 0
EXPOSE 8081
And the docker-compose.yml file:
version: '3'
services:
profittrailer:
container_name: profittrailer
image: "doccie/profittrailer:latest"
volumes:
- /home/[user]/.profittrailer:/app/ProfitTrailer
restart: unless-stopped
ports:
- "8081:8081"
The output logged (inside the container) is:
profittrailer | [PM2] Spawning PM2 daemon with pm2_home=/root/.pm2
profittrailer | [PM2] PM2 Successfully daemonized
profittrailer | [PM2][ERROR] File pm2-ProfitTrailer.json not found
I managed to get it working by not sharing the entire app directory, but limiting it to the folders and files I needed for configuration editing and migration.
version: '3'
services:
profittrailer:
container_name: profittrailer
image: "doccie/profittrailer:latest"
volumes:
- /home/[USERNAME]/.profittrailer/data:/app/ProfitTrailer/data
- /home/[USERNAME]/.profittrailer/application.properties:/app/ProfitTrailer/application.properties
restart: unless-stopped
ports:
- "8081:8081"
I needed to set up the application.properties file first, since otherwise, it would create the file as a folder instead.
Dockerfile:
FROM node:lts-slim AS base
# Install dependencies
RUN apt-get update \
&& apt-get install --no-install-recommends -y openssl
# Create app directory
WORKDIR /usr/src
FROM base AS builder
# Files required by npm install
COPY package*.json ./
# Files required by prisma
COPY prisma ./prisma
# Install app dependencies
RUN npm ci
# Bundle app source
COPY . .
# Build app
RUN npm install -g prisma --force
RUN prisma generate
RUN npm run build \
&& npm prune --omit=dev
FROM base AS runner
# Copy from build image
COPY --from=builder /usr/src/node_modules ./node_modules
COPY --from=builder /usr/src/dist ./dist
COPY --from=builder /usr/src/package*.json ./
COPY prisma ./prisma
RUN apt-get update \
&& apt-get install --no-install-recommends -y procps openssl
RUN chown -R node /usr/src/node_modules
RUN chown -R node /usr/src/dist
RUN chown -R node /usr/src/package*.json
USER node
# Start the app
EXPOSE 80
CMD ["node", "dist/index.js"]
docker-compose.yml
version: '3'
services:
mysql:
image: mysql:latest
container_name: mysql
ports:
- 3306:3306
bot:
container_name: bot
build:
context: .
depends_on:
- mysql
docker-compose.prod.yml
version: '3'
services:
mysql:
volumes:
- ./mysql:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: '123123'
MYSQL_DATABASE: 'test'
MYSQL_USER: 'test'
MYSQL_PASSWORD: '123123'
bot:
ports:
- "3000:80"
env_file:
- docker-compose.prod.bot.env
volumes:
mysql:
for some reason after running this commands:
docker-compose -f docker-compose.yml -f docker-compose.prod.yml run bot npx prisma migrate deploy
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up
im getting an error when the bot container running up, that he cant find any node module...
im using ubuntu 20.4 to run docker inside, installed docker and for some reason only this part is not working, wehn im running a build on normal machine without docker, build is working fine.
The only problem is with the docker.
error:
bot | node:internal/modules/cjs/loader:936
bot | throw err;
bot | ^
bot |
bot | Error: Cannot find module 'envalid'
bot | Require stack:
bot | - /usr/src/dist/config.js
In the process of integrating the docker file into my previous sample project so everything was automated for easy code sharing and execution. I have some dockerize problem and tried to solve it but to no avail. Hope someone can help. Thank you. Here is my problem:
My repository: https://github.com/ThanhDeveloper/WebApplicationAspNetCoreTemplate
Branch for dockerize (my problem in macOS):
https://github.com/ThanhDeveloper/WebApplicationAspNetCoreTemplate/pull/1
Docker file:
# syntax=docker/dockerfile:1
FROM node:16.11.1
FROM mcr.microsoft.com/dotnet/sdk:5.0
RUN apt-get update && \
apt-get install -y wget && \
apt-get install -y gnupg2 && \
wget -qO- https://deb.nodesource.com/setup_6.x | bash - && \
apt-get install -y build-essential nodejs
COPY . /app
WORKDIR /app
RUN ["dotnet", "restore"]
RUN ["dotnet", "build"]
RUN dotnet tool restore
EXPOSE 80/tcp
RUN chmod +x ./entrypoint.sh
CMD /bin/bash ./entrypoint.sh
Docker compose:
version: "3.9"
services:
web:
container_name: backendnet5
build: .
ports:
- "5005:5000"
depends_on:
- database
database:
container_name: postgres
image: postgres:latest
ports:
- "5433:5433"
environment:
- POSTGRES_PASSWORD=admin
volumes:
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
Commands:
docker-compose build
docker compose up
Problems:
I guess the problem is not being able to run command line dotnet ef database update my migrations. Many thanks for any help.
In your appsettings.json file, you say that the database hostname is 'localhost'. In a container, localhost means the container itself.
Docker compose creates a bridge network where you can address each container by it's service name.
You connection string is
User ID=postgres;Password=admin;Host=localhost;Port=5432;Database=sample_db;Pooling=true;
but should be
User ID=postgres;Password=admin;Host=database;Port=5432;Database=sample_db;Pooling=true;
You also map port 5433 on the database to the host, but postgres listens on port 5432. If you want to map it to port 5433 on the host, the mapping in the docker compose file should be 5433:5432. This is not what's causing your issue though. This just prevents you from connecting to the database from the host, if you need to do that.
I'm trying to setup a docker environment in which multiple containers communicate with each other via REST. My simplified system architecture looks somewhat like this:
Let's say I have two services foo and bar, that run on a node server (NestJS projects). The Dockerfile for both look something like this:
FROM node:14-alpine
ENV NODE_ENV=production \
NPM_CONFIG_PREFIX=/home/node/.npm-global \
PATH=$PATH:/home/node/.npm-global/bin:/home/node/node_modules/.bin:$PATH
RUN apk add --no-cache tini
RUN apk add iputils
RUN mkdir -p /usr/src/app/node_modules
RUN chown -R node:node /usr/src/app
USER node
WORKDIR /usr/src/app
COPY --chown=node:node package*.json ./
RUN npm ci --only=production
RUN npm cache clean --force
COPY --chown=node:node . ./
RUN ls -l
EXPOSE 80
ENTRYPOINT ["/sbin/tini", "--"]
CMD [ "npm", "start" ]
The docker-compose looks like this:
version: "3.8"
services:
foo:
image: "node:14-slim"
container_name: foo-service.${ENV}
build:
context: .
dockerfile: Dockerfile
args:
env: ${ENV}
port: ${PORT}
user: "node"
working_dir: /usr/src/app
environment:
- NODE_ENV=production
- VERSION=1.0
volumes:
- .:/usr/src/app
- /usr/app/node_modules
ports:
- ${PORT}:80
tty: true
command: "npm start"
networks:
my-network:
aliases:
- foo-service.${ENV}
networks:
my-network:
driver: "bridge"
name: my-network
I connect the containers via the my-network and made sure (docker network inspect my-network) that both containers share the same network. I can even ping one another (docker exec [foo] ping [bar])
When I'm running the application (making a REST call from the web interface) to foo, foo is then unable to "connect" to bar. I call bar from foo using the alias like this:
this.httpService.get('http://bar-service.dev:3002/...').
I get this error message:
I guess the containers still know each other since the DNS is resolved automatically by docker (I made sure that the IP-Address of bar is correct).
After some hours of trial and error and research I'd like to ask you guys. It might be an issue with alpine (some people had issues pinging node servers before). But it's also just as likely that I missed something important all along and can't seem to realize it...
Thanks in advance!
When I try to run node as a docker container with a non-root user, it says:
ERROR: for node Cannot start service node: OCI runtime create failed: container_linux.go:348: starting container process caused "chdir to cwd (\"/foo\") set in config.json failed: permission denied": unknown
My docker-compose.yml looks like this:
...
node:
image: node:latest
container_name: my_node_thingy
ports:
- "3003:3000"
user: "node"
working_dir: /foo
volumes:
- /var/project:/foo/
command: "node /foo/app.js"
networks:
- my-network
...
When I set "root" as the user, it works fine but when creating a new one by doing the following, the container wont start:
adduser --disabled-password --gecos '' node
adduser node sudo
echo "node ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/node
Could someone please explain to me how to set up the user properly?
If you have permission to do chmod -R 777 /var/project, please do it, then everything is ok, you can continue use user: node.
If you do not have permission, why not clone your code in a folder which you have a permission then repeat above?
If you still persist to say you want to make the Dockerfile suitable for more rugged environment. Then you may have to use gosu.
You need to define a new dockerfile inherit from node:latest, in the dockerfile, install gosu.
Something like follows:
FROM node:latest
RUN GOSU_SHA=5ec5d23079e94aea5f7ed92ee8a1a34bbf64c2d4053dadf383992908a2f9dc8a \
&& curl -sSL -o /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.9/gosu-$(dpkg --print-architecture)" \
&& chmod +x /usr/local/bin/gosu \
&& echo "$GOSU_SHA /usr/local/bin/gosu" | sha256sum -c -
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
And, in entrypoint.sh you need first use gosu to change the permission of /foo, then start your nodejs project.
Finally, remove command in docker-compose.yml.
Maybe change the permission of volume at host is the quicker way.