I'm trying to write a docker image to run a simple webserver though netcat.
So I have in my docker build folder:
Dockerfile
index.html
run_netcat_webserver.sh
The run_netcat_webserver.sh is very simple and it works fine:
#!/bin/bash
while true ; do nc -l 8080 < index.html ; done
Here is my naive Dockerfile that of course is not working:
FROM ubuntu:14.04
CMD run_netcat_webserver.sh
How should I proceed to make this work inside a docker container?
You need to make the script part of the container. To do that, you need to copy the script inside using the COPY command in the Docker file, e.g. like this
FROM ubuntu:14.04
COPY run_netcat_webserver.sh /some/path/run_netcat_webserver.sh
CMD /some/path/run_netcat_webserver.sh
The /some/path is a path of your choice inside the container. Since you don't need to care much about users inside the container, it can be even just /.
Another option is to provide the script externally, via mounted volume. Example:
FROM ubuntu:14.04
VOLUME /scripts
CMD /scripts/run_netcat_webserver.sh
Then, when you run the container, you specify what directory will be mounted as /scripts. Let's suppose that your script is in /tmp, then you run the container as
docker run --volume=/tmp:/scripts (rest of the command options and arguments)
This would cause that your (host) directory /tmp would be mounted under the /scripts directory of the container.
Simple example
Write a "Dockerfile"
FROM ubuntu:14.04 - # image you are using for building the container
ENTRYPOINT ["/bin/echo"] - # command that will execute when container is booted
Verify that you are in the same directory as the "Dockerfile".
sudo docker build .
and you are done
sample output:
ahanjura#ubuntu:~$ vi Dockerfile
ahanjura#ubuntu:~$ sudo docker build .
Sending build context to Docker daemon 1.39 GB
Step 1 : FROM ubuntu:14.04
---> 67759a80360c
Step 2 : ENTRYPOINT /bin/echo
---> Running in c0e5f48f7d45
---> 7a96b36f528e
Removing intermediate container c0e5f48f7d45
Successfully built 7a96b36f528e
Related
I'm trying to run a docker-compose build command with a Dockerfile and a docker-compose.yml file.
Inside the docker-compose.yml file, I'm trying to bind a local folder on the host machine ./dist with a folder on the container app/dist.
version: '3.8'
services:
dev:
build:
context: .
volumes:
- ./dist:app/dist # I'm expecting files to be changed or added to the container's app/dist to be reflected to the host's ./dist folder
Inside the Dockerfile, I build some files with an NPM script that I'm wanting to make available on the host machine once the build is finished. I'm also touching a new file inside the /app/dist/test.md just as a simple test to see if the file ends up on the host machine, but it does not.
FROM node:8.17.0-alpine as example
RUN mkdir /app
WORKDIR /app
COPY . /app
RUN npm install
RUN npm run dist
RUN touch /app/dist/test.md
Is there a way to do this? I also tried using the "long syntax" as mentioned in the Docker Compose v3 documentation: https://docs.docker.com/compose/compose-file/compose-file-v3/
The easiest way to do this is to install Node and run the npm commands directly on the host.
$BREW_OR_APT_GET_OR_YUM_OR_SOMETHING install node
npm install
npm run dist
# done
There's not an easy way to use a Dockerfile to build host content. The Dockerfile can't write out directly to the host filesystem; if you use a volume mount, the host volume hides the container content before anything else happens.
That means, if you want to use this approach, you need to launch a temporary container to get the content out. You can do it with a one-off container, mounting the host directory somewhere other than /app, making the main container command be cp:
sudo docker build -t myimage .
sudo docker run --rm \
-v "$PWD/dist:/out" \
myimage \
cp -a /app/dist /out
Or, if you specifically wanted to use docker cp:
sudo docker build -t myimage .
sudo docker create --name to-copy myimage
sudo docker cp -r to-copy:/app/dist ./dist
sudo docker rm to-copy
Note that any of these sequences are more complex than just installing a local Node via a package manager, and require administrator permissions (you can use the same technique to overwrite any host file, including the /etc/shadow file with encrypted passwords).
I have read the docs about CMD and ENTRYPOINT
https://docs.docker.com/engine/reference/builder/#entrypoint
Here, they have mentioned in the table that "NO CMD and NO ENTYRPOINT is not allowed", But I created a Dockerfile without CMD and ENTRYPOINT and the image was built successfully.
Download alpine tar from here Alpine Tar
Dockerfile
from scratch
ADD alpine-minirootfs-3.11.2-x86_64.tar.gz /
COPY . /
Building the image:
docker build -t test:1 .
Sending build context to Docker daemon 2.724MB
Step 1/3 : from scratch
-----
Successfully tagged test:1
docker run -ti test:1 /bin/sh
/ #
It worked!! So why in the docs it's mentioned that either CMD or ENTRYPOINT is necessary?
Specifying a command at the end of the docker run command line supplies (or overrides) CMD; similarly, the docker run --entrypoint option supplies (or overrides) ENTRYPOINT. In your example you gave a command /bin/sh so there's something for the container to do; if you leave it off, you'll get an error.
As a matter of style your Dockerfiles should almost always declare a CMD, unless you're extending a base image that's already running the application automatically (nginx, tomcat). That will let you docker run the image and launch the application embedded in it without having to remember a more specific command-line invocation.
The following line from documentation is incorrect.
Dockerfile should specify at least one of CMD or ENTRYPOINT commands.
It should probably say -
CMD or ENTRYPOINT is necessary for running a container.
I am trying to use a custom Dockerfile to build the LUIS container and copy the app file (app exported from the Luis portal) into the container. For this reason, I really don't need the mount points, since the .gz file will already live in the container. Is this possible? It seems that the mount points are always required...
I have to copy the files into the container and the move them to the input location at runtime (using an init.sh script). But, even then the container seemed to not load the app correctly. It behaves differently from that scenario compared to just putting the file in the host folder and mounting that to the container.
UPDATE: When I try to move the files around internally (at the start of the container), LUIS gives this output:
Using '/input' for reading models and other read-only data.
Using '/output/luis/fbfb798892fd' for writing logs and other output data.
Logging to console.
Submitting metering to 'https://southcentralus.api.cognitive.microsoft.com/'.
warn: Microsoft.AspNetCore.Server.Kestrel[0]
Overriding address(es) 'http://+:80'. Binding to endpoints defined in UseKestrel() instead.
Hosting environment: Production
Content root path: /app
Now listening on: http://0.0.0.0:5000
Application started. Press Ctrl+C to shut down.
fail: Luis[0]
Failed while prefetching App: AppId: d6fa5fd3-c32a-44d5-bb7f-d563775cf6ee - Slot: PRODUCTION Could not find file '/input/d6fa5fd3-c32a-44d5-bb7f-d563775cf6ee_PRODUCTION.gz'.
fail: Luis[0]
Failed while getting response for AppId: d6fa5fd3-c32a-44d5-bb7f-d563775cf6ee - Slot: PRODUCTION. Error: Could not find file '/input/d6fa5fd3-c32a-44d5-bb7f-d563775cf6ee_PRODUCTION.gz'.
warn: Microsoft.CloudAI.Containers.Controllers.LuisControllerV3[0]
Response status code: 404
Exception: Could not find file '/input/d6fa5fd3-c32a-44d5-bb7f-d563775cf6ee_PRODUCTION.gz'. SubscriptionId='' RequestId='d7dfee25-05d9-4af6-804d-58558f55465e' Timestamp=''
^C
nuc#nuc-NUC8i7BEK:/tmp/input$ sudo docker exec -it luis bash
root#fbfb798892fd:/app# cd /input
root#fbfb798892fd:/input# ls
d6fa5fd3-c32a-44d5-bb7f-d563775cf6ee_production.gz
root#fbfb798892fd:/input# ls -l
total 8
-rwxrwxrwx 1 root root 4960 Dec 2 17:35 d6fa5fd3-c32a-44d5-bb7f-d563775cf6ee_production.gz
root#fbfb798892fd:/input#
Notice that even though I can log into the container and browse the location of the model files and they are present, LUIS cannot load/find them.
UPDATE #2 - posting my Dockerfile:
FROM mcr.microsoft.com/azure-cognitive-services/luis:latest
ENV Eula=accept
ENV Billing=https://southcentralus.api.cognitive.microsoft.com/
ENV ApiKey=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ENV Logging:Console:LogLevel:Default=Debug
RUN mkdir /app/inputfiles/
RUN chmod 777 /app/inputfiles/
COPY *.gz /app/inputfiles/
WORKDIR /app
COPY init.sh .
RUN chmod 777 /app/init.sh
ENTRYPOINT /app/init.sh && dotnet Microsoft.CloudAI.Containers.Luis.dll
Option 1
The models can be COPY'd directly into /input/.
e.g.
FROM mcr.microsoft.com/azure-cognitive-services/luis:latest
COPY *.gz /input/
This will work, but requires that you don't mount to /input at runtime as it will squash the COPY'd files. The message "A folder must be mounted" is only logged if the /input directory does not exist.
> docker build . -t luis --no-cache
Sending build context to Docker daemon 40.43MB
Step 1/2 : FROM aicpppe.azurecr.io/microsoft/cognitive-services-luis
---> df4e32e45b1e
Step 2/2 : COPY ./*.gz /input/
---> c5f41a9d8522
Successfully built c5f41a9d8522
Successfully tagged luis:latest
> docker run --rm -it -p 5000:5000 luis eula=accept billing=*** apikey=***
...
Using '/input' for reading models and other read-only data.
...
Application started. Press Ctrl+C to shut down.
Option 2
The configuration value Mounts:Input can be set to configure the input location.
This might be useful if you need your models to live in /app/inputfiles or if you need to mount to /input for another reason at runtime.
e.g.
FROM aicpppe.azurecr.io/microsoft/cognitive-services-luis
ENV Mounts:Input=/app/inputfiles
COPY ./*.gz /app/inputfiles/
This results in:
> docker build . -t luis --no-cache
Sending build context to Docker daemon 40.43MB
Step 1/3 : FROM aicpppe.azurecr.io/microsoft/cognitive-services-luis
---> df4e32e45b1e
Step 2/3 : ENV Mounts:Input=/app/inputfiles
---> Running in b6029a2b54d0
Removing intermediate container b6029a2b54d0
---> cb9a4e06463b
Step 3/3 : COPY ./*.gz /app/inputfiles/
---> 9ab1dfaa36e7
Successfully built 9ab1dfaa36e7
Successfully tagged luis:latest
> docker run --rm -it -p 5000:5000 luis eula=accept billing=*** apikey=***
...
Using '/app/inputfiles' for reading models and other read-only data.
...
Application started. Press Ctrl+C to shut down.
It's true that the input mount won't be necessary if your .gz file is already in the image, but the output mount is used for logging and you may still want that for active learning purposes.
To build your desired image, create a text file named Dockerfile (no extension) and populate it with the following lines:
FROM mcr.microsoft.com/azure-cognitive-services/luis:latest
ENV Eula=accept
ENV Billing={ENDPOINT_URI}
ENV ApiKey={API_KEY}
COPY ./{luisAppId}_PRODUCTION.gz /input/{luisAppId}_PRODUCTION.gz
You can find your {ENDPOINT_URI} and your {API_KEY} using the normal LUIS container instructions, and {luisAppId} will be found in the name of your .gz file of course. Once your Dockerfile is ready, run it from the same folder that contains your .gz file with this command:
docker build -t luis .
Your image will now be ready. All your teammate has to do is run this command:
docker run --rm -it -p 5000:5000
--memory 4g
--cpus 2
--mount type=bind,src={OUTPUT_FOLDER},target=/output luis
{OUTPUT_FOLDER} can be any local absolute path you want as long as it exists. You may also omit the output mount if you don't want any logging:
docker run --rm -it -p 5000:5000 --memory 4g --cpus 2 luis
I am trying to build a docker image using the dockerfile, my purpose is to copy a file into a specific folder when i run the "docker run" command!
this my dockerfile code:
FROM openjdk:7
MAINTAINER MyPerson
WORKDIR /usr/src/myapp
ENTRYPOINT ["cp"]
CMD ["/usr/src/myapp"]
CMD ls /usr/src/myapp
After building my image without any error (using the docker build command), i tried to run my new image:
docker run myjavaimage MainClass.java
i got this error: ** cp: missing destination file operand after ‘MainClass.java’ **
How can i resolve this? thx
I think you want this Dockerfile:
FROM openjdk:7
WORKDIR /usr/src/myapp
COPY MainClass.java .
RUN javac MainClass.java
ENV CLASSPATH=/usr/src/myapp
CMD java MainClass
When you docker build this image, it COPYs your Java source file from your local directory into the image, compiles it, and sets some metadata telling the JVM where to find the resulting .class files. Then when you launch the container, it will run the single application you've packaged there.
It's common enough to use a higher-level build tool like Maven or Gradle to compile multiple files into a single .jar file. Make sure to COPY all of the source files you need in before running the build. In Java it seems to be common to build the .jar file outside of Docker and just COPY that in without needing a JDK, and that's a reasonable path too.
In the Dockerfile you show, Docker combines ENTRYPOINT and CMD into a single command and runs that command as the single main process of the container. If you provide a command of some sort at the docker run command, that overrides CMD but does not override ENTRYPOINT. You only get one ENTRYPOINT and one CMD, and the last one in the Dockerfile wins. So you're trying to run container processes like
# What's in the Dockerfile
cp /bin/sh -c "ls /usr/src/myapp"
# Via your docker run command
cp MainClass.java
As #QuintenScheppermans suggests in their answer you can use a docker run -v option to inject the file at run time, but this will happen after commands like RUN javac have already happened. You don't really want a workflow where the entire application gets rebuilt every time you docker run the container. Build the image during docker build time, or before.
Two things.
You have used CMD twice.
CMD can only be used once, think of it as the purpose of your docker image. Every time a container is run, it will always execute CMD if you want multiple commands, you should use RUN and then lastly, used CMD
FROM openjdk:
MAINTAINER MyPerson
WORKDIR /usr/src/
ENTRYPOINT ["cp"]
RUN /usr/src/myapp
RUN ls /usr/src/myapp
Copying stuff into image
There is a simple command COPY the syntax being COPY <from-here> <to-here>
Seems like you want to run myjavaimage so what you will do is
COPY /path/to/myjavaimage /myjavaimage
CMD myjavaimage MainClass.java
Where you see the arrows, I've just written dummy code. Replace that with the correct code.
Also, your Dockerfile is badly created.
ENTRYPOINT -> not sure why you'd do "cp", but it's an actual entrypoint. Could point to the root dir of your project or to an app that will be run.
Don't understand why you want to do ls /usr/src/myapp but if you do want to do it, use RUN and not CMD
Lastly,
Best way to debug docker containers are in interactive mode. That means ssh'ing in to your container, have a look around, run code, and see what is the problem.
Run this: docker run -it <image-name> /bin/bash and then have a look inside and it's usually the best way to see what causes issues.
This stackoverflow page perfectly answers your question.
COPY foo.txt /data/foo.txt
# where foo.txt is the relative path on host
# and /data/foo.txt is the absolute path in the image
If you need to mount a file when running the command:
docker run --name=foo -d -v ~/foo.txt:/data/foo.txt -p 80:80 image_name
I am creating one docker image name with soaphonda.
the code of docker file is below
FROM centos:7
FROM python:2.7
FROM java:openjdk-7-jdk
MAINTAINER Daniel Davison <sircapsalot#gmail.com>
# Version
ENV SOAPUI_VERSION 5.3.0
COPY entry_point.sh /opt/bin/entry_point.sh
COPY server.py /opt/bin/server.py
COPY server_index.html /opt/bin/server_index.html
COPY SoapUI-5.3.0.tar.gz /opt/SoapUI-5.3.0.tar.gz
COPY exit.sh /opt/bin/exit.sh
RUN chmod +x /opt/bin/entry_point.sh
RUN chmod +x /opt/bin/server.py
# Download and unarchive SoapUI
RUN mkdir -p /opt
WORKDIR /opt
RUN tar -xvf SoapUI-5.3.0.tar.gz .
# Set working directory
WORKDIR /opt/bin
# Set environment
ENV PATH ${PATH}:/opt/SoapUI-5.3.0/bin
EXPOSE 3000
RUN chmod +x /opt/SoapUI-5.3.0/bin/mockservicerunner.sh
CMD ["/opt/bin/entry_point.sh","exit","pwd", "sh", "/Users/ankitsrivastava/Documents/SametimeFileTransfers/Honda/files/hondascript.sh"]
My image creation is getiing successfull. I want that once the image creation is done it should retag and push in the docker hub. For that i have created the script which is below;
docker tag soaphonda ankiksri/soaphonda
docker push ankiksri/soaphonda
docker login
docker run -d -p 8089:8089 --name demo ankiksri/soaphonda
containerid=`docker ps -aqf "name=demo"`
echo $containerid
docker exec -it $containerid bash -c 'cd ../SoapUI-5.3.0;sh /opt/SoapUI-5.3.0/bin/mockservicerunner.sh "/opt/SoapUI-5.3.0/Honda-soapui-project.xml"'
Please help me how i can call the second script from docker file and the exit command is not working in docker file.
What you have to understand here is what you are specifying within the Dockerfile are the commands that gets executed when you build and run a Docker container from the image you have created using your Dockerfile.
So Docker image tag, push running should all done after you have built the Docker image from the Dockerfile. It cannot be done within the Dockerfile itself.
To achieve this kind of a thing you would have to use a build tool like Maven (an example) and automate the process of tagging, pushing the image. Also by looking at your image, I don't see any nessactiy to keep on tagging and pushing the image unless you are continuously updating the image. Also there is no point of using three FROM commands as it will unnecessarily make your Docker image size huge.