Can't run EF in a docker container as non root - entity-framework

I have the following docker file:
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["myapp.database/src/myapp.database.csproj", "myapp.database/"]
COPY ["myapp.database/src/NuGet.config", "myapp.database/"]
RUN dotnet restore "myapp.database/myapp.database.csproj"
COPY myapp.database/src myapp.database
WORKDIR /src/myapp.database
RUN dotnet build "myapp.database.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "myapp.database.csproj" -c Release -o /app/publish
FROM build AS final
RUN groupadd -g 500 dotnetuser && \
useradd -r -u 500 -g dotnetuser dotnetuser
RUN dotnet tool install --global dotnet-ef --version 3.1.0
ENV PATH="${PATH}:/root/.dotnet/tools"
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "myapp.database.dll"]
I create a user "dotnetuser" with uid as 500. I specify the following in my docker-compose:
version: '3.4'
services:
postgres:
image: postgres:12.1-alpine
ports:
- "5432:5432"
environment:
POSTGRES_USER: myapp
POSTGRES_PASSWORD: myapp
POSTGRES_DB: myapp
volumes:
- postgresvolume:/var/lib/postgresql/data
networks:
- dockercomposedatabase_default
myapp.database:
depends_on:
- postgres
user: "500"
build:
context: ..
dockerfile: myapp.database/build/Dockerfile
environment:
DOTNET_CLI_HOME: "/tmp/DOTNET_CLI_HOME"
networks:
- dockercomposedatabase_default
volumes:
postgresvolume:
external: false
networks:
dockercomposedatabase_default:
external: true
However, I can only run EF commands from my container if I run the container as root.
If I run as dotnetuser, then I get the following error:
Could not execute because the specified command or file was not found.
Possible reasons for this include:
* You misspelled a built-in dotnet command.
* You intended to execute a .NET Core program, but dotnet-ef does not exist.
* You intended to run a global tool, but a dotnet-prefixed executable with this name could not be found on the PATH.
I've tried various ways to get the dotnetuser to run ef commands as non-root, but without any success :(
Even if I install the tools to the dotnetuser home path, I still get issues with permissions.
How can I run dotnet ef database update if I run the docker as non-root?

It turns out that what I wanted to do wasn't possible. That is because EF will try to build even if you ship the compiled binaries. On immutable images, you won't be able to execute the EF tools. https://github.com/dotnet/efcore/issues/13339
However, there is a workaround I found on this Blog mentioned on the github issue: https://mattmillican.com/blog/ef-core-migrations-on-linux
Of course in my case, things were a little different. I changed my docker and created a migration.sh script.
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["myapp.database/src/myapp.database.csproj", "myapp.database/"]
COPY ["myapp.database/src/NuGet.config", "myapp.database/"]
COPY ["myapp.database/src/migration.sh", "myapp.database/"]
RUN dotnet restore "myapp.database/myapp.database.csproj"
COPY myapp.database/src myapp.database
WORKDIR /src/myapp.database
RUN dotnet build "myapp.database.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "myapp.database.csproj" -c Release -o /app/publish
RUN chmod +x /app/publish/migration.sh
FROM build AS final
RUN groupadd -g 500 dotnetuser && \
useradd -r -u 500 -g dotnetuser dotnetuser
RUN mkdir /tools
RUN dotnet tool install dotnet-ef --tool-path /tools --version 3.1.0
ENV PATH="${PATH}:/tools:/app"
WORKDIR /app
COPY --chown=dotnetuser:dotnetuser --from=publish /app/publish .
RUN rm -r /src
RUN chown dotnetuser:dotnetuser -R /tools
RUN chown dotnetuser:dotnetuser -R /app
USER dotnetuser
ENTRYPOINT ["migration.sh"]
I used my migration.sh script to execute the migration and then execute my myapp.database.dll to run my fixtures.
#!/bin/sh
# MIGRATION_NAME is an environmental variable for specifying the which migration to migrate to. It will allow you to migrate forward and back. Don't set the environmental value if you want to migrate to the latest migration.
# This path is important but may change between upgrades!!!
EF_DLL_PATH=/tools/.store/dotnet-ef/3.1.0/dotnet-ef/3.1.0/tools/netcoreapp3.1/any/tools/netcoreapp2.0/any/ef.dll
# standard compiled files for dotnet
DEPS_FILE=myapp.database.deps.json
RUNTIME_CONFIG=myapp.database.runtimeconfig.json
# assembly name
PROJECT_NAME=myapp.database
cd /app
echo "Executing the migration script..."
dotnet exec --depsfile ${DEPS_FILE} --runtimeconfig ${RUNTIME_CONFIG} "${EF_DLL_PATH}" database update ${MIGRATION_NAME} --context MyAppDbContext --assembly ${PROJECT_NAME}.dll --startup-assembly ${PROJECT_NAME}.dll --root-namespace ${PROJECT_NAME} || {
echo "Could not execute the migration!"
exit 1
}
echo "migration to ${MIGRATION} complete!"
echo "Run the fixtures..."
dotnet myapp.database.dll
echo "Fixtures applied!"
Hope this can helps someone.

Related

running elixir on buildkite with docker-compose fails with dependencies

i have the following dockerfile for an elixir+phoenix app
FROM elixir:latest as build_base
RUN apt-get -y update
RUN apt-get -y install inotify-tools curl
ARG TARGETARCH
RUN if [ ${TARGETARCH} = arm64 ]; then \
curl -L -o /tmp/dart-sass.tar.gz https://github.com/sass/dart-sass/releases/download/1.54.5/dart-sass-1.54.5-linux-${TARGETARCH}.tar.gz \
;else \
curl -L -o /tmp/dart-sass.tar.gz https://github.com/sass/dart-sass/releases/download/1.54.5/dart-sass-1.54.5-linux-x64.tar.gz \
;fi
RUN tar -xvf /tmp/dart-sass.tar.gz -C /tmp
RUN mv /tmp/dart-sass/sass /usr/local/bin/sass
RUN mkdir -p /app
WORKDIR /app
COPY mix.* ./
RUN mix local.hex --force
RUN mix archive.install hex phx_new --force
RUN mix local.rebar --force
RUN mix deps.clean --all
RUN mix deps.get
RUN mix --version
RUN mix deps.compile
COPY assets assets
COPY vendor vendor
COPY lib lib
COPY config config
COPY priv priv
COPY test test
RUN mix compile
the docker-compose file looks like the following
services:
web:
build:
context: .
dockerfile: Dockerfile
target: build_base
volumes:
- ./:/app
ports:
- "80:80"
command: mix phx.server
I'm trying to run docker-compose as part of the build step in buildkite, this is an extract of the step in buildkite
- label: "run web"
key: "web"
commands:
- mix phx.server
plugins:
- docker-compose#v4.9.0:
run: web
config: docker-compose.yml
however when running web i see everything happens properly including the package installation, however when running the application i see the following error
web_1 | Unchecked dependencies for environment dev:
web_1 | * telemetry_metrics (Hex package)
web_1 | the dependency is not available, run "mix deps.get"
and the list goes on and on, this works fine on my local machine, its only when running on buildkite. does anyone have any idea on how to fix this ?

Dockerfile for Go and Postgres

I need to make a Docker container with Go-app and Postgres db with migrated tables. All what I could find is combinations of these topics (1, 2)
Dockerfile
FROM golang:alpine as builder
RUN apk update && apk add --no-cache git
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -o main .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
COPY --from=builder /app/.env .
EXPOSE 8080
RUN chmod +x ./main
CMD ["./main"]
And I've got error standard_init_linux.go:219: exec user process caused: exec format error
I found that this is probably due to incompatibility of systems and architectures (I have Windows nd Intel x64), but none of the decisions helped.
Can you help me with Dockerfile or with my error?

Can't run command from docker file

I'm currently trying to dockerize a .net core API on my laptop but when I'm building the docker file I have some issue.
I have an issue when it's trying to execute commands like choco or wget. It says that they are not recognized, I did install them though and added as variables into my environment. They do work when I try to execute them independently in a terminal.
Here my script:
FROM microsoft/dotnet:2.2-sdk AS dotnet-builder
ARG nuget_pat
# Set environment variables
ENV NUGET_CREDENTIALPROVIDER_SESSIONTOKENCACHE_ENABLED true
ENV VSS_NUGET_EXTERNAL_FEED_ENDPOINTS '{"endpointCredentials":[{"endpoint":"https://isirac.pkgs.visualstudio.com/_packaging/RentacarMicroserviceNuget/nuget/v3/index.json","username":"NoRealUserNameAsIsNotRequired","password":"'${nuget_pat}'"}]}'
RUN choco install wget
# Get and install the Artifact Credential provider
RUN wget -O - https://raw.githubusercontent.com/Microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh | bash
# Restore your nugets from nuget.org and your private feed.
# RUN dotnet restore -s "https://isirac.pkgs.visualstudio.com/_packaging/RentacarMicroserviceNuget/nuget/v3/index.json" -s "https://api.nuget.org/v3/index.json" "Suzuki.csproj"
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-nanoserver-1909 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-nanoserver-1909 AS build
WORKDIR "/src/Suzuki/Suzuki/"
COPY ["*.csproj", "./"]
# COPY --from=nuget-config NuGet.config ./
RUN dotnet restore --interactive "Suzuki.csproj" -s "https://isirac.pkgs.visualstudio.com/_packaging/RentacarMicroserviceNuget/nuget/v3/index.json" -s "https://api.nuget.org/v3/index.json"
COPY . .
WORKDIR "/src/Suzuki/Suzuki/"
RUN dotnet build "Suzuki.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Suzuki.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Suzuki.dll"]
Does anyone have a clue?
thanks
Hi and welcome on Stackoverflow!
I could see some issues with your Dockerfile and the first one should be related to your issue. You use choco but you didn't install it before.
You could add a RUN to add it:
RUN powershell -Command \
iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')); \
choco feature disable --name showDownloadProgress
Another problem I see is how you use the multistage build of Docker. It's not a bug or something like that, but it could be better and easier to read.
Everytime you add a FROM instruction, you start a new image and you have the ability to copy some files from previous images.
In your Dockerfile, you have one step that is not really used:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-nanoserver-1909 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
From this stage, you didn't copy anything and do nothing. You will reuse it later but we need to read up to find the step as we may miss it. Later I will merge it with the final steps.
Another stage I don't understand:
FROM build AS publish
RUN dotnet publish "Suzuki.csproj" -c Release -o /app/publish
Why not running the command directly on the build image?
You have your file available in the publish image because you start from build that copy them, but, in this case, you can continue to use build directly.
And finally, the last stage:
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Suzuki.dll"]
If we use the base image declare previously, you just add some instructions to it and have a duplicate one: WORKDIR is the declare in the two place with the same value. I think, the best is to have a final stage that merge the two and be like this:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-nanoserver-1909
EXPOSE 80
EXPOSE 443
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Suzuki.dll"]
You don't need to name it as you will not use it after.
So, if we catch up, this is the Dockerfile I would purpose:
FROM microsoft/dotnet:2.2-sdk AS dotnet-builder
ARG nuget_pat
# Set environment variables
ENV NUGET_CREDENTIALPROVIDER_SESSIONTOKENCACHE_ENABLED true
ENV VSS_NUGET_EXTERNAL_FEED_ENDPOINTS '{"endpointCredentials":[{"endpoint":"https://isirac.pkgs.visualstudio.com/_packaging/RentacarMicroserviceNuget/nuget/v3/index.json","username":"NoRealUserNameAsIsNotRequired","password":"'${nuget_pat}'"}]}'
RUN powershell -Command \
iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')); \
choco feature disable --name showDownloadProgress; \
choco install wget
# Get and install the Artifact Credential provider
RUN wget -O - https://raw.githubusercontent.com/Microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh | bash
# Restore your nugets from nuget.org and your private feed.
# RUN dotnet restore -s "https://isirac.pkgs.visualstudio.com/_packaging/RentacarMicroserviceNuget/nuget/v3/index.json" -s "https://api.nuget.org/v3/index.json" "Suzuki.csproj"
WORKDIR "/src/Suzuki/Suzuki/"
COPY *.csproj ./
# COPY --from=nuget-config NuGet.config ./
RUN dotnet restore --interactive Suzuki.csproj -s "https://isirac.pkgs.visualstudio.com/_packaging/RentacarMicroserviceNuget/nuget/v3/index.json" -s "https://api.nuget.org/v3/index.json"
COPY . .
RUN dotnet build "Suzuki.csproj" -c Release -o /app/build
RUN dotnet publish "Suzuki.csproj" -c Release -o /app/publish
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-nanoserver-1909
EXPOSE 80
EXPOSE 443
WORKDIR /app
COPY --from=dotnet-builder /app/publish .
ENTRYPOINT ["dotnet", "Suzuki.dll"]

CircleCI 2.0 testing with docker-compose and code checkout

This is my circle.yml:
version: 2
jobs:
build:
working_directory: /app
docker:
- image: docker:stable-git
steps:
- checkout
- setup_remote_docker
- run:
name: Install dependencies
command: |
apk add --no-cache py-pip bash
pip install docker-compose
- run:
name: Start service containers and run tests
command: |
docker-compose -f docker-compose.test.yml up -d db es redis
docker-compose run web bash -c "cd myDir && ./manage.py test"
This works fine in that it brings up my service containers (db, es, redis) and I build a new image for my web container. However, my working code is not inside the freshly built image (so "cd myDir" always fails).
I figure the following lines in my Dockerfile should make my code available when it's built but it appears that it doesn't work like that:
ENV APPLICATION_ROOT /app/
RUN mkdir -p $APPLICATION_ROOT
WORKDIR $APPLICATION_ROOT
ADD . $APPLICATION_ROOT
What am I doing wrong and how can I make my code available inside my test container?
Thanks,
Use COPY, Your Dockerfile should look something like this.
FROM image
COPY . /opt/app
WORKDIR "/opt/app"
(More commands)
ENTRYPOINT

pg_dump server and pg_dump version mismatch in docker

When I run the command psql --version within the railsApp container, I get 9.4.12 and when I run the same within the postgres container, I get 9.6.2. How can I get the versions to match?
I am getting the following error when I try to do a migration on Rails App which does a pg_dump sql import.
pg_dump: server version: 9.6.2; pg_dump version: 9.4.12
pg_dump: aborting because of server version mismatch
rails aborted!
Here's my Docker-compose.yml file:
version: "2.1"
services:
railsApp:
build:
context: ./
ports:
- "3000:3000"
links:
- postgres
volumes:
- .:/app
postgres:
image: postgres:9.6
ports:
- "5432:5432"
volumes:
- ./.postgres:/var/lib/postgresql
The Dockerfile:
FROM ruby:2.3.3
# setup /app as our working directory
RUN mkdir /app
WORKDIR /app
# Replace shell with bash so we can source files
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
# Set debconf to run non-interactively
RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
# Install base dependencies
FROM ruby:2.3.3
# setup /app as our working directory
RUN mkdir /app
WORKDIR /app
# Replace shell with bash so we can source files
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
# Set debconf to run non-interactively
RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
# Install base dependencies
RUN apt-get update && apt-get install -y -q --no-install-recommends \
apt-transport-https \
build-essential \
ca-certificates \
curl \
git \
libssl-dev \
python \
rsync \
software-properties-common \
wget \
postgresql-client \
graphicsmagick \
&& rm -rf /var/lib/apt/lists/*
# Install node and npm with nvm
RUN curl https://raw.githubusercontent.com/creationix/nvm/v0.33.0/install.sh | bash
ENV NVM_DIR=/root/.nvm
ENV NODE_VERSION v7.2.1
ENV NODE_PATH $NVM_DIR/versions/node/$NODE_VERSION
ENV PATH $NODE_PATH/bin:./node_modules/.bin:$PATH
RUN source $NVM_DIR/nvm.sh \
&& nvm install $NODE_VERSION \
&& nvm alias default $NODE_VERSION \
&& nvm use default
# Install our ruby dependencies
ADD Gemfile Gemfile.lock /app/
RUN bundle install
# copy the rest of our code over
ADD . /app
ENV RAILS_ENV development
ENV SECRET_KEY_BASE a6bdc5f788624f00b68ff82456d94bf81bb50c2e114b2be19af2e6a9b76f9307b11d05af4093395b0471c4141b3cd638356f888e90080f8ae60710f992beba8f
# Expose port 3000 to the Docker host, so we can access it from the outside.
EXPOSE 3000
# Set the default command to run our server on port 3000
CMD ["rails", "server", "-p", "3000", "-b", "0.0.0.0"]
The same issue for me, I used an alternative way to take a dump,
First I access the terminal and run the pd_dump inside docker and copied the file from docker to host.
Below are the commands
docker exec -it <container-id> /bin/bash # accessing docker terminal
pg_dump > ~/dump # taking dump inside the docker
docker cp <container-id>:/root/dump ~/dump #copying the dump files to host
Hope the above solution helps.
The easiest approach is to use the correct postgres version in the docker-compose. Change:
postgres:
image: postgres:9.6
To:
postgres:
image: postgres:9.4.2
All available versions here.