Multiple Dockerfiles re-using shared library in project - docker

I have the following code structure and I am trying to structure my Dockerfile(s) as to maximize caching and the like.
serverfoo/
Dockerfile
main.go
serverbar/
Dockerfile
main.go
proto/
Dockerfile
sharedproto.proto // Generates a sharedproto.pb.go file to be imported.
Both serverfoo and serverbar import the compiled sharedproto.pb.go file which I manually regenerate on my workstation. This works fine but now I am attempting to containerize my two servers.
The Dockerfiles with my server folders cannot (by default) copy proto/ content. Ideally I pre-compile the protobufs into a sharedproto.pb.go then import a cached version of that file into the two server Dockerfiles. The goal is to cache the compiled protobufs until the underlying protos are modified.
I am new to Docker and need some best practice for this type of thing. I want to avoid a root Dockerfile in my project's directory that just has code to compile a zillion different servers.
I am open to restructuring my project to some degree.

NOTE: I suppose your target is to have on the specific server
container both the compiled go file ( from specific main.go file )
and the compiled protocol buffer file ( from shared
sharedproto.proto file ).
Assuming your files are organized as follow on your workstation:
serverfoo/
Dockerfile
main.go
serverbar/
Dockerfile
main.go
proto/
Dockerfile
sharedproto.proto
You can structure the specific server Dockerfile using the multistage build as follow ( e.g. serverbar Dockerfile ):
#####
# The serverbar Dockerfile
#####
#----
# Compile proto stage
#----
FROM moul/protoc-gen-gotemplate AS protostage
WORKDIR /workspace
# Copy .proto file
COPY proto/sharedproto.proto .
# Compile .pb.go
RUN protoc -I=. --go_out=. sharedproto.proto
#----
# Build stage
#----
FROM golang:1.12.4-alpine3.9 as buildstage
WORKDIR /workspace
COPY serverbar/main.go .
RUN GOOS=linux GOARCH=amd64 go build -o serverbar main.go
#----
# Final stage
#----
FROM alpine:3.7
WORKDIR /home
COPY --from=buildstage workspace/serverbar .
COPY --from=protostage workspace/sharedproto.pb.go .
CMD ["./serverbar"]
Using this approach you basically have the following 3 stages:
proto stage: On the container created on this stage you need to compile the shared protocol buffer source file into the sharedproto.pb.go that then will be included on the third final stage. So here you would need to install on the container the protoc compiler and the related Go plugin. However, as usual with Docker, you'll find a docker image that already includes your needed tools. For this purpose we can start from the moul/protoc-gen-gotemplate docker image.
Specifically the follow Dockerfile instruction generates the workspace/sharedproto.pb.go:
RUN protoc -I=. --go_out=. sharedproto.proto
build stage: Here you need to compile the server source file into the executable one. Also this will be included on the third final stage. To avoid to install Golang we can start from the golang:1.12.4-alpine3.9 docker image that already includes all the needed tools.
Specifically the follow Dockerfile instruction generates the workspace/serverbar executable:
RUN GOOS=linux GOARCH=amd64 go build -o serverbar main.go
final stage: This is the server container that we'll then upload on our Docker registry for test or production where we'll copy the files compiled on the previous two stage with the following commands:
COPY --from=buildstage workspace/serverbar .
COPY --from=protostage workspace/sharedproto.pb.go .
One of the advantages of this solution is that, for each server build, you can cache the compiled protobufs until the underlying protos are modified.
Example:
Building first time the serverbar container we can note that .proto compilation is performed on a new container with id 92ae211bd27d:
> docker build -f serverbar/Dockerfile .
Sending build context to Docker daemon 10.24kB
Step 1/13 : FROM moul/protoc-gen-gotemplate AS protostage
---> 635345fde953
Step 2/13 : WORKDIR /workspace
---> Using cache
---> de8890a5e775
Step 3/13 : COPY proto/sharedproto.proto .
---> 1253fa0576aa
Step 4/13 : RUN protoc -I=. --go_out=. sharedproto.proto
---> Running in 8426f5810b98
Removing intermediate container 8426f5810b98
---> 92ae211bd27d <=========================================
Step 5/13 : FROM golang:1.12.4-alpine3.9 as buildstage
---> b97a72b8e97d
Step 6/13 : WORKDIR /workspace
....
Building then a second time without modifying the sharedproto.proto we can note that container with id 92ae211bd27d is re-used from cache.
> docker build -f serverbar/Dockerfile .
Sending build context to Docker daemon 10.24kB
Step 1/13 : FROM moul/protoc-gen-gotemplate AS protostage
---> 635345fde953
Step 2/13 : WORKDIR /workspace
---> Using cache
---> de8890a5e775
Step 3/13 : COPY proto/sharedproto.proto .
---> Using cache
---> 1253fa0576aa
Step 4/13 : RUN protoc -I=. --go_out=. sharedproto.proto
---> Using cache <=========================================
---> 92ae211bd27d
Step 5/13 : FROM golang:1.12.4-alpine3.9 as buildstage
---> b97a72b8e97d
....

Related

no such file or directory in COPY dockerfile

I have made the following dockerfile to contain my node js application, the problem is that an error appears when building the dockerfile:
Sending build context to Docker daemon 2.048kB
Step 1/7 : FROM node:10
---> 0d5ae56139bd
Step 2/7 : WORKDIR /usr/src/app
---> Using cache
---> 5bfc0405d8fa
Step 3/7 : COPY package.json ./
COPY failed: stat /var/lib/docker/tmp/docker-
builder803334317/package.json: no such file or directory
this is my dockerfile:
FROM node:10
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD [ "npm", "start" ]
i executed the command:
sudo docker build - < Dockerfile
into my root project folder.
My project folder is simple, like this:
-Project
-app.js
-Dockerfile
-package.json
-package-lock.json
-README.md
I am doing something wrong?
When you use the Dockerfile-on-stdin syntax
sudo docker build - < Dockerfile
the build sequence runs in a context that only has the Dockerfile, and no other files on disk.
The directory layout you show is pretty typical, and pointing docker build at that directory should work better
sudo docker build .
(This is the same rule as the "Dockerfiles can't access files in parent directories" rule, but instead of giving the current directory as the base directory to Docker, you're giving no directory at all, so it can't even access files in the current directory.)

Go 1.11 unknown import path for own package in Docker build

I am migrating some code to work with Go 1.11 modules, and I am able to build it from the shell but not in Docker.
Relevant Dockerfile sections:
WORKDIR /goscout
COPY ["go.mod", "go.sum", "./"]
RUN GO111MODULE=on go get -u=patch
COPY *.go ./
RUN GO111MODULE=on go build -v -ldflags "-linkmode external -extldflags -static" -o GoScout -a .
When Docker is running the last command in the above excerpt, I get this error:
can't load package: package github.com/triplestrange/StrangeScout/goscout: unknown import path "github.com/triplestrange/StrangeScout/goscout": ambiguous import: found github.com/triplestrange/StrangeScout/goscout in multiple modules:
github.com/triplestrange/StrangeScout/goscout (/goscout)
github.com/triplestrange/StrangeScout v0.3.0 (/go/pkg/mod/github.com/triplestrange/!strange!scout#v0.3.0/goscout)
I don't get this in the shell, so I'm guessing I am not copying some files correctly. But before this command runs I have copied go.mod, go.sum, and *.go, so I don't know what could be missing.
Make sure that you initialized modules properly for your project
go mod init github.com/triplestrange/StrangeScout/goscout
so that the content of your go.mod is
module github.com/triplestrange/StrangeScout/goscout
And then you can use your current Dockerfile without any changes.
There is no need to set GO111MODULE=on since you're running go commands outside of the $GOPATH
➜ docker build -t goscout .
Sending build context to Docker daemon 47.1kB
Step 1/11 : FROM golang:latest AS builder
---> fb7a47d8605b
Step 2/11 : WORKDIR /goscout
---> Running in e9786fe5ab53
Removing intermediate container e9786fe5ab53
---> 6d101e346175
Step 3/11 : COPY ./ ./
---> 7081c0b47dc9
Step 4/11 : RUN go get -d -v ./...
---> Running in 3ce69359ae88
go: finding github.com/go-sql-driver/mysql v1.4.0
go: finding github.com/gorilla/mux v1.6.2
go: downloading github.com/gorilla/mux v1.6.2
go: downloading github.com/go-sql-driver/mysql v1.4.0
Removing intermediate container 3ce69359ae88
...
---> 3df0dbca80e5
Successfully built 3df0dbca80e5
Successfully tagged goscout:latest

The most basic docker build fails on COPY

I'm trying to build a docker image for this first time out of the exeutables for a VS project that is already compiled. I do not want docker to build my project (oh no given the problems I already have). As a result I have the following Dockerfile in the folder where my app source files (and compiled binaries) are:
Location: d:\MyApp
Dockerfile Contents:
FROM microsoft/windowsservercore
COPY bin /app
ENTRYPOINT ["C:\\app\\x86\\Debug\\MyApp.exe"]
Contents of MyApp folder:
MyApp\
MyApp\bin
MyApp\bin\x64
MyApp\bin\x64\Release
MyApp\bin\x64\Debug
MyApp\bin\x64\Release\* (lots of binaries)
MyApp\bin\x64\Debug\* (lots of binaries)
...
MyApp\Dockerfile
Command window:
d:\MyApp> docker image build .
Sending build context to Docker daemon 3.584kB
Step 1/3 : FROM microsoft/windowsservercore ---> 4dba31379dad
Step 2/3 : COPY bin /app COPY failed: CreateFile \\?\C:\ProgramData\Docker\tmp\docker-builder196938557\bin: The system cannot find the file specified.
If I change the COPY line to COPY ./bin/*.* /app/ :
Sending build context to Docker daemon 3.584kB
Step 1/3 : FROM microsoft/windowsservercore
---> 4dba31379dad
Step 2/3 : COPY ./bin/*.* /app/
COPY failed: no source files were specified
Somehow I had a ".dockerignore" with a "*" in it. After removing that line everything seems to be ok.

Docker: COPY failed: CreateFile, looking for file in strange location

Trying to follow the tutorial found here, but running into problems.
I run the following command from my project dir:
docker build -t my.solution .
I get the following:
Sending build context to Docker daemon 111.6kB
Step 1/17 : FROM microsoft/aspnetcore:2.0-nanoserver-1709 AS base
---> ccfb41c8f5b5
Step 2/17 : WORKDIR /app
---> Using cache
---> e29a68e16001
Step 3/17 : EXPOSE 80
---> Using cache
---> 976388139964
Step 4/17 : FROM microsoft/aspnetcore-build:2.0-nanoserver-1709 AS build
---> d7ab4e860769
Step 5/17 : WORKDIR /src
---> Using cache
---> 4ab01220723e
Step 6/17 : COPY my.solution.sln ./
COPY failed: CreateFile \\?\C:\ProgramData\Docker\tmp\docker-builder564035917\my.solution.sln: The system cannot find the file specified.
I don't know why it's trying to find the file in the location it's looking for it. Can anyone help me? Is there a config setting I need to make? My Docker file looks like this:
FROM microsoft/aspnetcore:2.0-nanoserver-1709 AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0-nanoserver-1709 AS build
WORKDIR /src
COPY my.solution.sln ./
COPY my.solution/my.solution.csproj my.solution/
RUN dotnet restore -nowarn:msb3202,nu1503
COPY . .
WORKDIR /src/my.solution
RUN dotnet build -c Release -o /app
FROM build AS publish
RUN dotnet publish -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "my.solution.dll"]
UPDATE
Per #AlexGera's answer, I tried changing my docker file to:
FROM microsoft/aspnetcore:2.0-nanoserver-1709 AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0-nanoserver-1709 AS build
WORKDIR /src
VOLUME C:/tmp
COPY my.solution.sln c:/tmp/
COPY my.solution/my.solution.csproj my.solution/
RUN dotnet restore -nowarn:msb3202,nu1503
COPY . .
WORKDIR /src/my.solution
RUN dotnet build -c Release -o /app
FROM build AS publish
RUN dotnet publish -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "my.solution.dll"]
but the error message doesn't change significantly:
docker build -t my.solution .
Sending build context to Docker daemon 111.6kB
Step 1/18 : FROM microsoft/aspnetcore:2.0-nanoserver-1709 AS base
---> ccfb41c8f5b5
Step 2/18 : WORKDIR /app
---> Using cache
---> e29a68e16001
Step 3/18 : EXPOSE 80
---> Using cache
---> 976388139964
Step 4/18 : FROM microsoft/aspnetcore-build:2.0-nanoserver-1709 AS build
---> d7ab4e860769
Step 5/18 : WORKDIR /src
Removing intermediate container 31e30e2346aa
---> 61c7df20f3c4
Step 6/18 : VOLUME C:/tmp
---> Running in fada6c728151
Removing intermediate container fada6c728151
---> 7a650440cc1f
Step 7/18 : COPY my.solution.sln c:/tmp/
COPY failed: CreateFile \\?\C:\ProgramData\Docker\tmp\docker-builder832533802\my.solution.sln: The system cannot find the file specified.
Seems to me the standard Dockerfile that comes with a new solution is bugged :/
I moved the Dockerfile up to the solution folder, from PowerShell:
mv Dockerfile ../Dockerfile
Running the docker build command from there did the trick for me...
The COPY command will copy the file from the build context, or a previous build stage if you specify the stage. With your build command:
docker build -t my.solution .
The context is . which is first sent to the docker engine which places that in a temporary location just for the build.
Therefore with your copy command:
Step 6/17 : COPY my.solution.sln ./
The file my.solution.sln needs to exist in the folder where the build command was run.
For the destination, the file will be copied to the working directory inside the container, or /src in your example.
This was probably caused by the .dockerignore file next to you DockerFile, ignoring everything but /obj/*.
Once you copied it to another folder you didn't copy the .dockerignore file, so nothing was excluded and it worked.
Before copying add a volume in your image to copy where to.
Something like this:
VOLUME C:/Users/mysolution
COPY my.solution.sln C:/Users/mysolution
Try not to use dots for directory names.
I found that same situation in a VS2017 Solution where the build is started by docker compose and yml files one directory above the project.
If you want to build by docker build with the docker file directly, you need to move the docker file one level above the context
Use the \\
FROM microsoft\\aspnetcore-build:2.0-nanoserver-1709 AS build
see the below example
FROM microsoft/aspnetcore:2
WORKDIR /app
EXPOSE 80
COPY bin\\Debug\\netcoreapp2.0 .
ENTRYPOINT ["dotnet","DOCKER-API.dll"]
I move my Dockerfile to the root folder (where exists .sln and .dockerignore files) and my problem was resolved
Perfect suits for who uses visual studio :
run this command :
docker build -t . your_application_name/Dockerfile
Dockerfile Copy path :
["your_application_name/your_application_name.csproj","your_application_name/"]
we run the build command docker build command it is unable to find the dockerfile in the project path location.
Visual Studio creates the Docker file at Project level, however, the Dockerfile is tailored to be run from an upper level (Solution level).
The easiest way to fix this problem is to go one level up (Solution folder), and specify the project folder:
docker build --tag tagone -f Project/Dockerfile .

Docker compose build error - Project file does not exist

I'm trying to create docker compose which run my ASP.NET Core app and mssql, but I'm getting an error during build.
Here's my docker compose file:
# Build Stage
FROM microsoft/aspnetcore-build:latest as build-env
WORKDIR /source
COPY . .
RUN dotnet restore ./Travelingowe.sln
RUN dotnet publish --output ${source:-obj/Docker/publish} --configuration Release
# Publish Stage
FROM microsoft/aspnetcore:latest
COPY --from=build-env ./obj/Docker/publish /app
WORKDIR /app
ENTRYPOINT ["dotnet", "Api.dll"]
when I run in CMD -> docker-compose up I'm getting:
Building api
Step 1/9 : FROM microsoft/aspnetcore-build:latest as build-env
---> d6273f7c44d4
Step 2/9 : WORKDIR /source
---> Using cache
---> 978f1c31e14a
Step 3/9 : COPY . .
---> Using cache
---> bcc750adcb99
Step 4/9 : RUN dotnet restore ./Travelingowe.sln
---> Running in 764199859de4
MSBUILD : error MSB1009: Project file does not exist.
Switch: ./Travelingowe.sln
ERROR: Service 'api' failed to build: The command '/bin/sh -c dotnet restore ./Travelingowe.sln' returned a non-zero code: 1
Do you have any ide what is wrong?
Thanks!
UPDATE:
My project files:
you have issues with your working directory try using absolute path instead of relative path in your working directory in docker file
TL;DR
Put your Dockerfile in your project root folder.
There are several question you need to think of:
Where is your Dockerfile?
How does docker-compose.yaml point to Dockerfile?
It seems like you put your Dockerfile in the other folder.
As document mentions:
Compose uses an alternate file to build with. A build path must also be specified.
When you use the Dockerfile on different folder with docker-compose.yaml you have to set up the context property.
As it set up, it will consider the Dockerfile's folder as project root folder. So when the command dotnet restore ./Travelingowe.sln executed, it shows you the error
You can manually test the command by running dotnet restore ./Travelingowe.sln in Dockerfile's folder. It should show the detail error message.

Resources