Skip to content
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

Wrap master node in docker container #296

Merged
merged 88 commits into from Dec 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
e4b682f
MasterNodeIntegrationSpec draft
DmiSergeev Nov 22, 2018
f8ce558
test asserts
DmiSergeev Nov 22, 2018
59f3b35
paths and resources updated
DmiSergeev Nov 22, 2018
0a86aec
minor
DmiSergeev Nov 22, 2018
982d222
node path changed
DmiSergeev Nov 22, 2018
dc44086
paths changes
DmiSergeev Nov 22, 2018
1f32b7f
cp/rm in containers
DmiSergeev Nov 23, 2018
b048da7
IPs changed
DmiSergeev Nov 23, 2018
946e7ca
increased wait time
DmiSergeev Nov 23, 2018
559bca3
IPs changed
DmiSergeev Nov 23, 2018
7f1d329
host temporarily changed to localhost
DmiSergeev Nov 23, 2018
48f34a5
minor
DmiSergeev Nov 23, 2018
0d99eaa
tracing net_info
DmiSergeev Nov 23, 2018
72f87b7
tracing os name
DmiSergeev Nov 23, 2018
5dc3c9a
checking another ports
DmiSergeev Nov 23, 2018
be8cfd1
docker host detection
DmiSergeev Nov 23, 2018
079388a
minor
DmiSergeev Nov 23, 2018
c020f9e
minor
DmiSergeev Nov 23, 2018
05f8d95
minor
DmiSergeev Nov 23, 2018
60cc112
running docker with API
DmiSergeev Nov 23, 2018
10d305f
commented code removed
DmiSergeev Nov 23, 2018
9eb664f
fix vm code path lookup in sbt runMain
folex Nov 26, 2018
da2ea23
Remove Thread.sleep
folex Nov 26, 2018
2fe82ff
Refactor eventually a bit
folex Nov 26, 2018
e789f62
refactor IP check
folex Nov 26, 2018
326ab35
Increase timeout
folex Nov 26, 2018
16ee197
Add ipv6 to checkIp
folex Nov 26, 2018
f498785
Remove redundant type check
folex Nov 26, 2018
00da66c
Increase timeouts further
folex Nov 26, 2018
ad934ee
Increase timeouts to 60 + 60 seconds
folex Nov 26, 2018
2f1b92b
Pull solver image before tests
folex Nov 26, 2018
46261ce
Timeouts = 30 + 30
folex Nov 26, 2018
4ac765a
timeouts = 60 + 60
folex Nov 26, 2018
1edadd7
Increase timeouts to 120 + 30. Add TODOs -_-
folex Nov 26, 2018
b2cd4bc
Fix error message
folex Nov 26, 2018
bd93831
Merge branch 'master' into network/integration-test
folex Nov 26, 2018
12be2cd
rename dir
folex Nov 27, 2018
dccd87b
Specify current user on tendermint init
folex Nov 27, 2018
837f3c2
Remove --user nonsense, create /tendermint directory before running s…
folex Nov 27, 2018
35df513
Try -> IO::attempt
folex Nov 28, 2018
4ed358b
IO -> F[_] in KeysPath, DockerParams.!! -> DockerIO, don't copy files…
folex Nov 28, 2018
e6aafc8
IO -> F[_]
folex Nov 28, 2018
83295f5
F[_] -> IO (funfunfun)
folex Nov 28, 2018
d9bfc78
Specify uid
folex Nov 28, 2018
8cf5dea
fix
folex Nov 28, 2018
12d4f21
Thread -> Concurrent[IO]
folex Nov 28, 2018
592b3f6
Refactor pipes
folex Nov 28, 2018
59305f0
WIP: Add assembly & docker plugin to node
folex Nov 28, 2018
c56ceee
Merge branch 'master' into network/node-docker
folex Nov 29, 2018
254b196
Wrap master in docker
folex Nov 29, 2018
6726890
a -> the
folex Nov 29, 2018
b2166cc
Merge branch 'master' into network/node-docker
folex Nov 29, 2018
86fb706
Generate application.conf in entrypoint.sh
folex Nov 29, 2018
dca16b7
Copy configs & code to solvers (and it works!)
folex Nov 30, 2018
dc680f3
Refactor run.sh
folex Nov 30, 2018
b1ad969
Refactor directory structure & add some comments
folex Nov 30, 2018
b2c7335
Fix import, add $PORTS
folex Nov 30, 2018
c4c5316
Move configuration logic from MasterNodeApp, add comments
folex Nov 30, 2018
960e538
Add implicit
folex Dec 2, 2018
fa0566f
Healthcheck
folex Dec 3, 2018
00adfa1
Comment MasterNodeIntegrationSpec
folex Dec 3, 2018
696c512
Fix integration test, add comments in entrypoint.sh
folex Dec 3, 2018
5445d66
Remove old code from CodeManager, fix exception hanlding in Configura…
folex Dec 3, 2018
f0719fc
fix compilation
folex Dec 3, 2018
646ebad
fix ip parsing
folex Dec 3, 2018
c20fd5e
fix typo
folex Dec 3, 2018
ced64d9
Rename master -> node
folex Dec 3, 2018
d5a007e
ubuntu -> alpine, use 2018-dec-demo tag in tests AND code
folex Dec 3, 2018
8634ced
use tag 2018-dec-demo in travis.yml
folex Dec 3, 2018
b9d02b9
Try to accumulate strings
folex Dec 3, 2018
6a0e198
Move docker image names to constants
folex Dec 3, 2018
3d923cd
remove println
folex Dec 3, 2018
a145610
Enable logs
folex Dec 3, 2018
baaa785
Ethereum IP
folex Dec 3, 2018
c201f6b
Read swarm ip from env
folex Dec 3, 2018
cefe105
Quote strings in config generated in entrypoint.sh
folex Dec 3, 2018
365d0d4
Ganache listen on 0.0.0.0
folex Dec 3, 2018
572b883
Merge branch 'master' into network/node-docker
folex Dec 3, 2018
92cc4c5
increase timeout
folex Dec 3, 2018
c4b74aa
Remove implicit
folex Dec 4, 2018
dedf8a3
Add comment
folex Dec 4, 2018
facfef4
minor pr fixes
folex Dec 4, 2018
b4af656
Move docker image to config
folex Dec 4, 2018
5348a81
Increase gas limit in publisher
folex Dec 4, 2018
529abae
Add docker-compose
folex Dec 4, 2018
27980d0
Add README.md
folex Dec 4, 2018
a12f754
add npm run getEthAccount
folex Dec 4, 2018
ffb9980
Update bootstrap/README.me
folex Dec 4, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -7,6 +7,7 @@ target/
# IntelliJ
.idea
.vscode
*.iml

# MacOS folder metadata
.DS_Store
Expand Down
3 changes: 2 additions & 1 deletion .travis.yml
Expand Up @@ -7,7 +7,8 @@ matrix:
services:
- docker
install:
- docker pull fluencelabs/solver:latest
- docker pull fluencelabs/solver:2018-dec-demo
Copy link
Member

Choose a reason for hiding this comment

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

Should it be merged to master?

Copy link
Member Author

@folex folex Dec 4, 2018

Choose a reason for hiding this comment

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

There problem is that I can't really release new docker images before I merge this PR to master, and tests in the PR won't pass before I release new docker images.

So this is a workaround, I will create the next pull request after I release new docker images as 'latest', where I will change images to latest everywhere.

- docker pull fluencelabs/node:2018-dec-demo

# These directories are cached to S3 at the end of the build
cache:
Expand Down
5 changes: 4 additions & 1 deletion bootstrap/README.md
Expand Up @@ -21,4 +21,7 @@ Then, copy & paste contract's address and your wallet into `ContractSpec` and ru
`npm run ganache`

## Run tests
`npm test`
`npm test`

## Get current eth account through truffle
`npm run getEthAccount`
3 changes: 2 additions & 1 deletion bootstrap/package.json
Expand Up @@ -8,7 +8,8 @@
"scripts": {
"test": "truffle test",
"migrate": "truffle migrate",
"ganache": "ganache-cli -m \"indicate toward book great daring meat tooth bid finger banana witness episode\" &",
"ganache": "ganache-cli -m \"indicate toward book great daring meat tooth bid finger banana witness episode\" -h 0.0.0.0 &",
"getEthAccount": "echo 'web3.eth.accounts[0]' | truffle console | grep -o \"0x.*\" | tr -d \\'",
"generate-java-wrapper": "scripts/generate_java_wrapper.sh",
"compile-sol": "node scripts/compile_sol.js",
"generate-all": "npm run compile-sol && npm run generate-java-wrapper"
Expand Down
63 changes: 52 additions & 11 deletions build.sbt
Expand Up @@ -113,20 +113,22 @@ lazy val statemachine = (project in file("statemachine"))
"net.i2p.crypto" % "eddsa" % "0.3.0",
scalaTest
),
assemblyJarName in assembly := "statemachine.jar",
assemblyMergeStrategy in assembly := {
// a module definition fails compilation for java 8, just skip it
case PathList("module-info.class", xs @ _*) => MergeStrategy.first
case x =>
val oldStrategy = (assemblyMergeStrategy in assembly).value
oldStrategy(x)
},
test in assembly := {},
imageNames in docker := Seq(ImageName("fluencelabs/solver")),
dockerfile in docker := {
// Run `sbt docker` to create image

// The assembly task generates a fat JAR file
val artifact: File = assembly.value
val artifactTargetPath = s"/app/${artifact.name}"
val artifact = assembly.value
val artifactTargetPath = s"/${artifact.name}"

// Tendermint constants
val tmVersion = "0.25.0"
Expand All @@ -145,11 +147,9 @@ lazy val statemachine = (project in file("statemachine"))
val vmDataRoot = "/vmcode"

new Dockerfile {
from("xqdocker/ubuntu-openjdk:jre-8")
run("apt", "-yqq", "update")
run("apt", "-yqq", "install", "wget", "curl", "jq", "unzip", "screen")
run("wget", tmBinaryUrl)
run("unzip", "-d", "/bin", tmBinaryArchive)
from("openjdk:8-jre-alpine")
// TODO: merge all these `run`s into a single run
runRaw(s"wget $tmBinaryUrl && unzip -d /bin $tmBinaryArchive && rm $tmBinaryArchive")

expose(tmP2pPort)
expose(tmRpcPort)
Expand All @@ -163,9 +163,9 @@ lazy val statemachine = (project in file("statemachine"))
// includes solver run script and default configs in the image
copy(baseDirectory.value / "docker" / "solver", solverDataRoot)

add(artifact, artifactTargetPath)
copy(artifact, artifactTargetPath)

entryPoint("bash", solverRunScript, tmDataRoot, solverDataRoot, artifactTargetPath)
entryPoint("sh", solverRunScript, artifactTargetPath)
}
}
)
Expand Down Expand Up @@ -224,7 +224,48 @@ lazy val node = project
circeGeneric,
circeParser,
scalaTest
)
),
assemblyMergeStrategy in assembly := {
// a module definition fails compilation for java 8, just skip it
case PathList("module-info.class", xs @ _*) => MergeStrategy.first
case "META-INF/io.netty.versions.properties" =>
MergeStrategy.first
case x =>
val oldStrategy = (assemblyMergeStrategy in assembly).value
oldStrategy(x)
},
mainClass in assembly := Some("fluence.node.MasterNodeApp"),
assemblyJarName in assembly := "master-node.jar",
test in assembly := {},
imageNames in docker := Seq(ImageName("fluencelabs/node")),
dockerfile in docker := {
// The assembly task generates a fat JAR file
val artifact: File = assembly.value
val artifactTargetPath = s"/${artifact.name}"

new Dockerfile {
// docker is needed in image so it can connect to host's docker.sock and run solvers on host
val dockerBinary = "https://download.docker.com/linux/static/stable/x86_64/docker-18.06.1-ce.tgz"
folex marked this conversation as resolved.
Show resolved Hide resolved
from("openjdk:8-jre-alpine")
runRaw(s"wget -q $dockerBinary -O- | tar -C /usr/bin/ -zxv docker/docker --strip-components=1")

volume("/master") // anonymous volume to store all data

/*
* The following directory structure is assumed in node/src/main/resources:
* docker/
* tendermint/config/default_config.toml
* vmcode/vmcode-llamadb/llama_db.wasm
* entrypoint.sh
*/
copy((resourceDirectory in Compile).value / "docker", "/master/")

copy(artifact, artifactTargetPath)

cmd("java", "-jar", artifactTargetPath)
entryPoint("sh", "/master/entrypoint.sh")
}
}
)
.enablePlugins(AutomateHeaderPlugin)
.enablePlugins(AutomateHeaderPlugin, DockerPlugin)
.dependsOn(ethclient, externalstorage)
2 changes: 1 addition & 1 deletion cli/src/publisher.rs
Expand Up @@ -94,7 +94,7 @@ impl Publisher {
let receipt: H256 =
"0000000000000000000000000000000000000000000000000000000000000000".parse()?;

let options = utils::options_with_gas(500_000);
let options = utils::options_with_gas(2_000_000);

utils::call_contract(
self.account,
Expand Down
57 changes: 57 additions & 0 deletions node/README.md
@@ -0,0 +1,57 @@
## How to run ganache
In order to run master node, you need to have any Ethereum RPC node. In this example we will use Ganache for that purpose. To run Ganache and deploy Fluence contract there, run
```
cd fluence/bootstrap

npm install
npm run ganache
npm run migrate
```

You will see address of the Deployer contract in your private Ganache blockchain:
```
Deployer: 0x9995882876ae612bfd829498ccd73dd962ec950a
```

Ganache is run in deterministic mode with predefined mnemonic, so this address will always be the same and there is no need to save it.

## How to run master node
Go to `fluence/tools/node` and run `docker-compose`:
```
cd fluence/tools/node

docker-compose -f single-master.yml up -dV
```

`single-master.yml` runs one Swarm container and one master node container with solver ports 25000-25003.

## How to run solvers

After having run master node, you need to upload and publish your WASM code to Swarm. In this example we will use `llamadb` that can be found at `fluence/node/src/main/resources/docker/vmcode/vmcode-llamadb/llama_db.wasm`. You can use Fluence `cli` to upload and publish it:
```
cd fluence/cli

cargo build --release

target/release/fluence publish ../node/src/main/resources/docker/vmcode/vmcode-llamadb/llama_db.wasm 0x9995882876ae612bfd829498ccd73dd962ec950a 0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d --cluster_size 1
```

You can take a look at `target/release/fluence publish --help` to get the idea of how it works. I will describe parameters briefly:

- `target/release/fluence` is a `cli` binary we compiled by running `cargo build --release`
- `publish` is a command that uploads code to Swarm and sends it to Ethereum contract (running on Ganache)
- `../node/src/main/resources/docker/vmcode/vmcode-llamadb/llama_db.wasm` is a path to llamadb compiled to WASM
- `0x9995882876ae612bfd829498ccd73dd962ec950a` is a Deployer contract address that was deployed by `npm run migrate`
- `0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d` is an Ethereum account address that's used for publishing code
- `--cluster_size 1` specifies number of nodes required to run this code. We ran single master node, so we specify 1 here.

## How to check solver is running fine
You can check solver's logs by issuing `docker logs 01_node0` (you may need to replace `01_node0` with the name of the solver container, see `docker ps`). Look for `Commit: processTime=23 height=2`, `processTime` could be anything, you're looking for `height=2`. It can appear after some time, usually 10-60 seconds, depending on your hardware.

## Cleaning up
- To clean up ALL docker containers, including volumes: `docker ps -a | awk '{print $1}' | xargs docker rm -f ; docker volume prune -f`
- To clean up docker-compose state: `docker-compose -f single-master.yml kill`
- To stop ganache: `pkill -f ganache`

## Troubleshooting
TODO
83 changes: 83 additions & 0 deletions node/src/main/resources/docker/entrypoint.sh
@@ -0,0 +1,83 @@
# Copyright 2018 Fluence Labs Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#!/usr/bin/env bash -e
folex marked this conversation as resolved.
Show resolved Hide resolved

###
# This script is an entrypoint of the Master docker container.
# It first checks that $TENDERMINT_IP and $PORTS are defined,
# if /var/run/docker.sock is passed as a volume, and
# then if running master-node.jar, generate application.conf,
# and run whatever command is passed as arguments (usually it's CMD from Dockerfile).
###

# set to fail fast
set -e

if [ -z "$TENDERMINT_IP" ]; then
cat >&2 <<EOF
error: \`-e "TENDERMINT_IP=your_external_ip"\` was not specified.
It is required so Tendermint instance can advertise its address to cluster participants
EOF
exit 1
fi

if [ -z "$PORTS" ]; then
cat >&2 <<EOF
error: \`-e "PORTS=start:stop"\` was not specified.
TODO: add more helpful explanation
EOF
exit 1
fi

if [ ! -S /var/run/docker.sock ]; then
cat >&2 <<EOF
error: '/var/run/docker.sock' not found in container or is not a socket.
Please, pass it as a volume when running the container: \`-v /var/run/docker.sock:/var/run/docker.sock\`
EOF
exit 1
fi

if [ -z "$ETHEREUM_IP" ]; then
ETHEREUM_IP=$TENDERMINT_IP
fi

SWARM_ENABLED="true"
if [ -z "$SWARM_IP" ]; then
SWARM_ENABLED="false"
fi

# Running master-node.jar, that means running default CMD
if [ "$3" = "/master-node.jar" ]; then
CONTAINER_ID=$(cat /proc/1/cpuset)
cat > "/master/application.conf" <<EOF
endpoints {
ip = "$TENDERMINT_IP"
min-port = ${PORTS%:*}
max-port = ${PORTS#*:}
}
ethereum {
host = "$ETHEREUM_IP"
}
swarm {
host = "$SWARM_IP"
enabled = "$SWARM_ENABLED"
}
tendermint-path = "/master"
master-container-id = "${CONTAINER_ID#"/docker/"}"
EOF
fi

# Execute whatever command is passed as arguments. Usually it's CMD from Dockerfile.
exec "$@"
24 changes: 22 additions & 2 deletions node/src/main/resources/reference.conf
@@ -1,16 +1,36 @@
// a path to a working directory, where all keys, configurations and codes files will be stored
tendermint-path = "target/.tendermint"

solver {
image = "fluencelabs/solver"
tag = "2018-dec-demo"
}

endpoints {
// IP address for all endpoints that will be used for solvers
ip = "127.0.0.1"
// ports that will be selected by the deployer smart contract
min-port = 20000
max-port = 20100
}

ethereum {
// ethereum RPC protocol
protocol = "http"

// ethereum RPC address
ip = "127.0.0.1"

// ethereum RPC port
port = 8545
}

// use the Swarm or run local precompiled code
use-swarm: true,
use-swarm: false,
swarm {
// the address to the Swarm gateway
host = "http://localhost:8500"
protocol = "http"
host = "localhost"
port = 8500
enabled = false
}
2 changes: 0 additions & 2 deletions node/src/main/scala/fluence/node/ConfigOps.scala
Expand Up @@ -37,9 +37,7 @@ object ConfigOps {
)
)
)

}

}

implicit val inetAddressConvert: ConfigConvert[InetAddress] =
Expand Down