Skip to content

Add Fn Dockerfile tip #145

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Fn is an event-driven, open source, [Functions-as-a-Service (FaaS)](https://gith
* [Create a Function with a Docker Container](https://fnproject.io/tutorials/ContainerAsFunction/)
* [Create a Function from a Docker image that contains a Node.js app with Oracle DB Support](https://fnproject.io/tutorials/node/custom-db/)
* [Create a Function with a Linux Command and HotWrap](https://fnproject.io/tutorials/docker/CustomLinuxContainer/)
* [Build a Function with a Dockerfile](fn/develop/build-function-dockerfile.md)
* [Logging and Debugging Tutorial](https://fnproject.io/tutorials/Troubleshooting/)
* [Function Debugging](fn/troubleshoot/debug-loglevel.md)
* [FAQ](fn/general/faq.md)
Expand Down
128 changes: 128 additions & 0 deletions fn/develop/build-function-dockerfile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Build Functions using Dockerfile
Fn uses Docker to deploy functions. Have your ever wondered, where is the `Dockerfile` that builds my image? Doesn't Docker need one?

The answer is yes, a `Dockerfile` is created and used during the function's build process. The Dockerfile is installed when the build process starts and deleted once the build is complete. But this begs the question, can I capture the Fn `Dockerfile`, tweak it, and use it to build my function? The answer is again yes.


## Capturing the Dockerfile
First, create a default Fn function which can be used to `build` or `deploy` our function.

(1) Create a "hello world" function and change into the function directory.

```sh
fn init --runtime python pyhello
cd pyhello
```

(2) Create an app so you can deploy your function.

```sh
fn create app pyapp
```

(3) Now, build your function with the verbose switch to see all the steps in the build process.

```sh
$ fn --verbose build
Building image fndemouser/pyhello:0.0.1
FN_REGISTRY: fndemouser
Current Context: default
Sending build context to Docker daemon 6.144kB
Step 1/13 : FROM fnproject/python:3.6-dev as build-stage
---> cdf5a7155ecc
Step 2/13 : WORKDIR /function
---> Using cache
---> 1a7c6d16ae63
Step 3/13 : ADD requirements.txt /function/
---> Using cache
---> 8df0fd7a59dc
Step 4/13 : RUN pip3 install --target /python/ --no-cache --no-cache-dir -r requirements.txt && rm -fr ~/.cache/pip /tmp* requirements.txt func.yaml Dockerfile .venv
---> Using cache
---> 165ef454bdfa
Step 5/13 : ADD . /function/
---> e6c8049eaec1
Step 6/13 : RUN rm -fr /function/.pip_cache
---> Running in d8b5784d8169
Removing intermediate container d8b5784d8169
---> 6bb78917832f
Step 7/13 : FROM fnproject/python:3.6
---> e33fde7116e2
Step 8/13 : WORKDIR /function
---> Using cache
---> d64051e4412d
Step 9/13 : COPY --from=build-stage /python /python
---> Using cache
---> da7edae08f48
Step 10/13 : COPY --from=build-stage /function /function
---> 6e1c7ccb069c
Step 11/13 : RUN chmod -R o+r /python /function
---> Running in 338003ba63a7
Removing intermediate container 338003ba63a7
---> fde0a3cc40ee
Step 12/13 : ENV PYTHONPATH=/function:/python
---> Running in 2cd7350ef0fd
Removing intermediate container 2cd7350ef0fd
---> 0f8310f595c6
Step 13/13 : ENTRYPOINT ["/python/bin/fdk", "/function/func.py", "handler"]
---> Running in 2bdb3d0fe39c
Removing intermediate container 2bdb3d0fe39c
---> d8a532969fda
Successfully built d8a532969fda
Successfully tagged fndemouser/pyhello:0.0.1

Function fndemouser/pyhello:0.0.1 built successfully.
```

If you have some familiarity with Dockerfiles, you should notice that each step looks pretty Docker-like.

(4) You can create a `Dockerfile.new` file using this command.

```sh
fn build --verbose | grep Step |> Dockerfile.new cut -d ' ' -f4-
```

**Note:** The command identifies each line with "Step" in it, then grabs the 4th field in the line and uses it to create `Dockerfile.new`.

The result, should be a `Dockerfile.new` that looks like this:

```dockerfile
FROM fnproject/python:3.6-dev as build-stage
WORKDIR /function
ADD requirements.txt /function/
RUN pip3 install --target /python/ --no-cache --no-cache-dir -r requirements.txt && rm -fr ~/.cache/pip /tmp* requirements.txt func.yaml Dockerfile .venv
ADD . /function/
RUN rm -fr /function/.pip_cache
FROM fnproject/python:3.6
WORKDIR /function
COPY --from=build-stage /python /python
COPY --from=build-stage /function /function
RUN chmod -R o+r /python /function
ENV PYTHONPATH=/function:/python
ENTRYPOINT ["/python/bin/fdk", "/function/func.py", "handler"]
```
You have your `Dockerfile.new`, but you need to make a couple more tweaks before you can use it.

(5) To finish up, you must configure `func.yaml` file. Run the following commands.

```sh
cp Dockerfile.new Dockerfile
rm func.yaml
fn init
```
Running the commands makes `fn` recognize the `Dockerfile` and creates a new `func.yaml` file. Which looks like this:

```yaml
schema_version: 20180708
name: pyhello
version: 0.0.1
runtime: docker
```

## Deploying your Function with Dockerfile
You can now deploy and test your function using a `Dockerfile`.

```sh
$ fn --verbose deploy --app pyapp --local
$ fn invoke pyapp pyhello
{"message": "Hello World"}
```