Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Dockerfile with config.json templating - Closes #2053 #2056

Merged
merged 7 commits into from
Jun 6, 2018

Conversation

fchavant
Copy link
Contributor

What was the problem?

Docker images are were being built from Dockerfile(s) in a different repository and were only configurable to a limited extent.

How did I fix it?

Added Dockerfile to this repository along with a template for config.json.

How to test it?

  • build docker image from top-level Dockerfile
  • ensure config.json can be customized by setting environment variables, e.g. LISK_DB_HOST

Review checklist

@fchavant fchavant self-assigned this May 24, 2018
@fchavant fchavant requested a review from diego-G May 24, 2018 14:19
@fchavant fchavant changed the title Dockerfile with config.json templating Dockerfile with config.json templating - Closes #2053 May 24, 2018
Copy link
Contributor

@hendrikhofstadt hendrikhofstadt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fchavant I appreciate that you added my config proposal/template to the repo here 👍 Is there a reason you are still using the full ubuntu image instead of the much smaller alpine one ?

Also will you completely remove liskhq/lisk-docker and keep the scripts in this repo for better managebility (as we also discussed a submodule approach)

Copy link
Contributor

@hendrikhofstadt hendrikhofstadt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a peer list to the dockerfile and nethash should be required to create a straightforward build and release process.

Dockerfile Outdated
ARG LISK_MIN_VERSION=${LISK_VERSION}
ENV LISK_VERSION ${LISK_VERSION}
ENV LISK_MIN_VERSION ${LISK_MIN_VERSION}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you are not adding the version specific seed peers here using

ENV LISK_PEERS_LIST_1 "94.237.41.99:5001"

ENV LISK_PEERS_LIST_2 "209.50.52.217:5001"

ENV LISK_PEERS_LIST_3 "94.237.26.150:5001"

ENV LISK_PEERS_LIST_4 "83.136.249.102:5001"

ENV LISK_PEERS_LIST_5 "94.237.65.179:5001"

Like here: LiskArchive/lisk-docker@c8b49ff#diff-ed9d43ac74c2d8e77f8497b190a5ab5aR23

For ease of release purposes the version specific nethash and seed peers should be set in this list, shouldn't they ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we add see nodes here then this Dockerfile becomes specific to a network (betanet given the peers you listed)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I thought you might want to do this because there are other network specific files on the repo and to maintain compatibility with the old Docker images. But since the Docker image is using the "next" version they are breaking anyway and the proposed adding of an extra file for the peers list is a very good idea.

@fchavant
Copy link
Contributor Author

fchavant commented May 25, 2018

@MaciejBaj not sure why the build was shown as "failing" (it was not); I started the build again and the checks are now I green.

@fchavant
Copy link
Contributor Author

@SLAMPER

Is there a reason you are still using the full ubuntu image instead of the much smaller alpine one ?

I am concerned the packages that build native code (e.g. sodium) might not work (properly) -- I just haven't had time to look into it.

Also will you completely remove liskhq/lisk-docker and keep the scripts in this repo for better managebility (as we also discussed a submodule approach)

In a first step we'll probably keep the docker-compose based examples in the lisk-docker repository.

@fchavant fchavant force-pushed the 2053-dockerfile-config-template branch from 2adbbae to 858c44e Compare May 25, 2018 13:01
Copy link

@diego-G diego-G left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about the Docker Cloud check? Is this going to be mandatory for every PR or is optional?

},
"peers": {
"enabled": {{getv "/lisk/peers/enabled" "true"}},
"list": [
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to insert another variable which it'd read a file having the peers list? We need to bear in mind the goal of having an network agnostic template.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If such a file were to be introduced I suppose we could. Another option would be to add an ARG and set it at build time.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, we will add a new file containing the list of peers when we tackle #398.

@hendrikhofstadt
Copy link
Contributor

@fchavant
The PR really looks good.

Another thing about nethash and seed peers. I think it's great that this is decoupled from the repo, which is a good step towards #398. Will you then add the required config variables to the docker-compose example.

This could be a good chance to you an .env-file for docker-compose which is network specific so the docker-compose.yml is not bloated and we have more decoupling.

About the Alpine image. I agree that there should be some testing before trying it out.
I tested a full Alpine version using confd some time ago and it worked just perfectly and had a much smaller size (about 70MB).

I can also open a PR with the adapted dockerfile so you can save time on it and request changes if you think any are necessary.

Dockerfile Outdated
WORKDIR /home/lisk/lisk

RUN npm install
RUN ./node_modules/.bin/grunt release
Copy link
Contributor

@hendrikhofstadt hendrikhofstadt May 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of doing grunt release ? I see that it adds files that mark the revision which can help identify the version but it also creates a packaged tarball and copies it to a release directory creating unnecessary bulk for the docker image.

If the build and revision files are necessary grunt build/revision should be enough and not create unnecessary files.

Still the best would be to do npm install --production to omit all the unnecessary devDependencies (including grunt and other build utils)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@diego-G can you chime in on this?

Copy link

@diego-G diego-G May 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fchavant I agree we don't need grunt release in the docker image. Regarding to the other comment, I prefer to keep npm install without --production flag. But It is true we should use NODE_ENV environment variable to signalise what kind of installation we want in the image. By default npm listens it, not installing devDependencies if it is set to production.

@hendrikhofstadt
Copy link
Contributor

@fchavant If you want to test the alpine image, here is a version of my alpine Dockerfile that I adapted with your changes: https://gist.github.com/Slamper/f96105fd4a130b15fd301c4315956fcf

It also omits the chown and uses COPY --chown instead which makes the build much quicker.

@fchavant
Copy link
Contributor Author

fchavant commented May 28, 2018

@SLAMPER thanks; I'll have a look as soon as everything is done here. The reason I am not using the --chown flag is that it's not supported in docker cloud yet (it's running docker version 17.06.2-ee-6)
It might make sense to add a comment so that we can change this in the future.

#!/bin/bash

confd -backend env -onetime
node app.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we are not using lisk.sh script here, if possible we should use it for consistency across distribution platforms.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not using lisk.sh here because

  • it is meant to manage an all-in-one installation which this is not and
  • it is meant to be run interactively: it starts processes and then returns which is not what the PID 1 of a container should do

#!/bin/bash

confd -backend env -onetime
node app.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally I noticed entrypoint.sh as startup file in different docker images, should we not follow that naming convention.

Copy link
Contributor Author

@fchavant fchavant May 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Often a docker-entrypoint.sh script is used in combination with ENTRYPOINT; note that we use CMD however.

@fchavant
Copy link
Contributor Author

@diego-G the ci/dockercloud check will only run for tags, not PR (except this one)

@fchavant fchavant force-pushed the 2053-dockerfile-config-template branch from b0d2ced to 83de841 Compare May 30, 2018 13:28
@MaciejBaj MaciejBaj requested a review from diego-G June 5, 2018 13:46
Dockerfile Outdated
@@ -0,0 +1,53 @@
FROM node:6 AS builder

ENV ENV_NODE=production
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convention is to use NODE_ENV, many libraries use this convention to check environment variable for production use case. So better to rename it.

Dockerfile Outdated

ENV ENV_NODE=production

RUN groupadd --gid 1100 lisk && \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't find any reference for using 1100 gid specific to distro. Why we are hardcoding the group id. What if some dependent docker container use the same group id?

Would it not be nice to add group only with name and then get its id afterwards. This may be helpful getent group lisk

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GID is not distribution specific. We chose 1100 arbitrarily.

What if some dependent docker container use the same group id?
That would be no problem in a different container. I you mean a container that mounts a volume from this one then that'd allow having the "same" lisk user (same UID and GID).

Dockerfile Outdated
ENV ENV_NODE=production

RUN groupadd --gid 1100 lisk && \
useradd --create-home --home-dir /home/lisk --shell /bin/bash --uid 1100 --gid 1100 lisk
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same applies to uid here.

Dockerfile Outdated
useradd --create-home --home-dir /home/lisk --shell /bin/bash --uid 1100 --gid 1100 lisk
# As of May 2018 cloud.docker.com runs docker 17.06.1-ce
# however version 17.12 is required to use the chown flag
COPY . /home/lisk/lisk/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't just copy every thing to docker. First run grunt release and copy the compiled source code. You may not find any noticeable difference, but any future change in Gruntfile may break the docker. So better to use compile release after grunt.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the build container, we must copy everything in order to be able to run npm install or grunt release. Regarding the latter I was told to remove it; @diego-G can you please confirm once more?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fchavant @diego-G I am sure we need to run grunt release and copy only the archive files to container.

@fchavant We can run npm install and grunt release on host machine, where we are actually building container. I think we don't need a seperate container just to run grunt release.

Copy link
Contributor Author

@fchavant fchavant Jun 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need a seperate container just to run grunt release.

It is a way to have a clean build environment w/o polluting the final containers with build time dependencies.

I am sure we need to run grunt release and copy only the archive files to container.

What would be the advantage in using the tarball grunt creates? It's meant to be consumed by lisk-build's build.sh script which makes sense for all-in-one release but not docker.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fchavant Nothing will be polluted, if you run grunt release on host machine and copy the archive build file to container. It will not contain node_modules directory. So you will do a clean npm install in container.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1/ I don't want to run anything on the host: that way anyone can build the image (also in Docker Cloud)
2/ by using a build container the final image does not contain any of the build dependencies (e.g. gcc)

A nice bonus of using a build container is that we always build in a clean environment.

RUN npm install


FROM node:6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a different container (the final one, not the build container)

"httpPort": {{getv "/lisk/httpport" "8000"}},
"address": "{{getv "/lisk/address" "0.0.0.0"}}",
"version": "{{getenv "LISK_VERSION"}}",
"minVersion": "{{getenv "LISK_MIN_VERSION"}}",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these env variables meant to run container with different min values, then I believe its not the right case. Once the docker container is built, its built for a specific version, which is bound to a specific minVersion. User should not be allowed to change those on runtime.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once the docker container is built, its built for a specific version, which is bound to a specific minVersion.
That is exactly what will happen, those environment variables will come from the docker image (see https://github.com/LiskHQ/lisk/blob/83de84142be1c7603941278be0d51f0a6c833abb/Dockerfile#L44)

"trustProxy": {{getv "/lisk/trustproxy" "false"}},
"topAccounts": {{getv "/lisk/topaccounts" "false"}},
"cacheEnabled": {{getv "/lisk/cacheenabled" "false"}},
"wsWorkers": {{getv "/lisk/wsworkers" "1"}},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why these variables are all small case? We follow either camel or snake can for readability.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confd will convert those depeding on the chosen backend: environment variables in our case. That means /lisk/wsworker will become LISK_WSWORKER and capitalization will get lost.

"host": "{{getv "/lisk/redis/host" "127.0.0.1"}}",
"port": {{getv "/lisk/redis/port" "6380"}},
"db": {{getv "/lisk/redis/db" "0"}},
"password": {{getv "/lisk/redis/password" "null"}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe here you want to set null instead of "null", consider null without quote means no password. But if you quote it will check for that password.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will output null not "null": notice there are not double quotes around the expression in double curly braces (compare to host for instance)

},
"peers": {
"enabled": {{getv "/lisk/peers/enabled" "true"}},
"list": [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the right use case for configurable values. User may want load its own list of peers. Can't understand why its should be done separately. Issue #398 is totally different thing, to support multiple networks in one installation.

@@ -0,0 +1,177 @@
#!/usr/bin/env bash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is not relevant to lisk docker image, so it should not be included here. Even we can't see any usage of this script file in our Dockerfile.

Its dependency is used by docker-composer under lisk-docker repo, so this script should be kept and managed there.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought on the topic further. If you really want lisk container to wait for db port to be available before running. Then use this script inside run.sh not inside the docker-compose. This will make sure that our image will always have this behavior. And then it also makes sense to make this script file part of this repo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No you are running the script in docker-compose.

Please do it in run.sh and in compose start the container. The run.sh file should have usage of wait-for-it.sh to wait for db to appear online and then run node app.js

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we were to call wait-for-it.sh in run.sh then

  • it would not be optional any more and
  • passing parameters (host and port of the db to wait for) would be akward.

I think it makes sense to keep it where optional and as it is right now (wait-for-it.sh waiting for the DB and then calling run.sh)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If its an optional then don't copy it in container through docker file.

That's clearly seems a utility script used in docker-compose, then keep it there, mount the utility scripts volume to container and run it.

If something not required or not related to an image, don't copy it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By optional I mean one can use it but one does not have to.
To give this possibility the script needs to be in the image though (the lisk container must wait for the postgres container; having it somewhere else would not work.

Copy link
Contributor

@nazarhussain nazarhussain Jun 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the lisk container must wait for the postgres container
Then make it part of run.sh

Having a utility script in image, but using it somewhere else (composer) does not make sense to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we make it part of run.sh the it becomes very much non optional. Also it would make passing parameters hard; see above.

Having a utility script in image, but not using it somewhere else (composer) does not make sense to me.

We have a script in the image, it can be used in one's docker-compose.yml or by swarm or rancher or whatever. Or one may choose not to use it. That's why I call it "optional".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fchavant Ok please document it somewhere our docker image have this script and the usage of this script.

@fchavant fchavant force-pushed the 2053-dockerfile-config-template branch from 690a39e to 2dfd350 Compare June 6, 2018 08:38
Copy link
Contributor

@nazarhussain nazarhussain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please document it somewhere our docker image have waitf-for-it script and its usage.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants