Skip to content

Commit

Permalink
docs(examples): containerize supply-chain-app
Browse files Browse the repository at this point in the history
Uses a Docker-in-Docker container to run the supply
chain app example which itself has functionality that
spawns docker containers to host the AIO ledger images.
This makes it a 100% turn-key way of providing examples
to anyone who have at least the ability to run docker
containers built for the linux amd64 platform.

Fixes #486

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
  • Loading branch information
petermetz committed Feb 16, 2021
1 parent 1fa24be commit 2b2c32c
Show file tree
Hide file tree
Showing 10 changed files with 364 additions and 54 deletions.
59 changes: 59 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
.git
*/*/node_modules
*/*/dist
*/*/build
whitepaper
docs
contribs
images
tools
packages/business-logic-plugin
packages/config
packages/ledger-plugin
packages/cactus-ledger-plugin
packages/routing-interface
packages/copyStaticAssets.ts
packages/jest.config.js

.config.json
.nyc_output/
dist/
.DS_Store
node_modules/
logs/
jspm_packages/
generated-sources/
coverage/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# next.js build output
.next

# vscode files
.vscode/*
!.vscode/template.launch.json

# Introperability App specifics
examples/simple-asset-transfer/fabric/**/hfc-key-store/

bin/
.tmp/
lerna-debug.log
cactus-openapi-spec.json
cactus-openapi-spec-*.json
.npmrc
*.log
31 changes: 14 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,20 @@ As blockchain technology proliferates, blockchain integration will become an inc

### Supply Chain Example

```sh
git clone https://github.com/hyperledger/cactus.git
cd cactus
npm install
npm run configure
cd examples/supply-chain-app/
npm install --no-package-lock
cd ../../
npm run build:dev
$ npm start:example-supply-chain
...
[2020-10-27T00:38:00.574Z] INFO (api-server): Cactus API reachable http://127.0.0.1:5000
[2020-10-27T00:38:00.574Z] INFO (api-server): Cactus Cockpit reachable http://127.0.0.1:6000
...
[2020-10-27T00:38:00.574Z] INFO (api-server): Cactus API reachable http://127.0.0.1:5100
[2020-10-27T00:38:00.574Z] INFO (api-server): Cactus Cockpit reachable http://127.0.0.1:6100
```
1. Run the following command to pull up the container that will run the example application and the test ledgers as well:
```sh
docker run \
--rm \
--privileged \
-p 3000:3000 \
-p 3100:3100 \
-p 4000:4000 \
-p 4100:4100 \
hyperledger/cactus-example-supply-chain-app:2021-02-05-f89a37a
```
2. Wait for the output to show the message `INFO (api-server): Cactus Cockpit reachable http://0.0.0.0:3100`
3. Visit http://localhost:3100 in a web browser with Javascript enabled
4. Use the graphical user interface to create data on both ledgers and observe that a consistent view of the data from different ledgers is provided.

Once the last command has finished executing, open link printed on the console with a web browser of your choice

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
#!/usr/bin/env node

import { ConfigService } from "@hyperledger/cactus-cmd-api-server";
import { LoggerProvider } from "@hyperledger/cactus-common";
import { ISupplyChainAppOptions, SupplyChainApp } from "./supply-chain-app";

export async function launchApp(cliOpts?: any): Promise<void> {
const appOptions: ISupplyChainAppOptions = { logLevel: "TRACE", ...cliOpts };
export async function launchApp(): Promise<void> {
const configService = new ConfigService();
const config = configService.getOrCreate();
const serverOptions = config.getProperties();
LoggerProvider.setLogLevel(serverOptions.logLevel);

const appOptions: ISupplyChainAppOptions = {
logLevel: serverOptions.logLevel,
};
const supplyChainApp = new SupplyChainApp(appOptions);
try {
await supplyChainApp.start();
} catch (ex) {
console.error(`SupplyChainApp crashed. Existing...`, ex);
await supplyChainApp.stop();
await supplyChainApp?.stop();
process.exit(-1);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ export class SupplyChainApp {
const keychainIdB = "PluginKeychainMemory_B";

// Reserve the ports where the Cactus nodes will run API servers, GUI
const httpApiA = await Servers.startOnPreferredPort(5000);
const httpApiB = await Servers.startOnPreferredPort(5100);
const httpGuiA = await Servers.startOnPreferredPort(6000);
const httpGuiB = await Servers.startOnPreferredPort(6100);
const httpApiA = await Servers.startOnPort(4000, "0.0.0.0");
const httpApiB = await Servers.startOnPort(4100, "0.0.0.0");
const httpGuiA = await Servers.startOnPort(3000, "0.0.0.0");
const httpGuiB = await Servers.startOnPort(3100, "0.0.0.0");

const addressInfoA = httpApiA.address() as AddressInfo;
const nodeApiHostA = `http://localhost:${addressInfoA.port}`;
Expand Down Expand Up @@ -299,27 +299,23 @@ export class SupplyChainApp {
httpServerCockpit: Server,
pluginRegistry: PluginRegistry,
): Promise<ApiServer> {
const addressInfo = httpServerApi.address() as AddressInfo;
const addressInfoApi = httpServerApi.address() as AddressInfo;
const addressInfoCockpit = httpServerCockpit.address() as AddressInfo;

const configService = new ConfigService();
const apiServerOptions = configService.newExampleConfig();
// FIXME: Plugin imports will only work once we have this merged and released in webpack
// https://github.com/webpack/webpack/pull/11316
apiServerOptions.plugins = [];

apiServerOptions.configFile = "";
apiServerOptions.apiCorsDomainCsv = "*";
apiServerOptions.apiPort = addressInfo.port;
apiServerOptions.apiTlsEnabled = false;
apiServerOptions.cockpitTlsEnabled = false;
apiServerOptions.cockpitPort = 0;
apiServerOptions.logLevel = this.options.logLevel || "INFO";
apiServerOptions.cockpitWwwRoot =
"./node_modules/@hyperledger/cactus-example-supply-chain-frontend/www/";
const config = configService.newExampleConfigConvict(apiServerOptions);
const config = configService.getOrCreate();
const properties = config.getProperties();

properties.plugins = [];
properties.configFile = "";
properties.apiPort = addressInfoApi.port;
properties.apiHost = addressInfoApi.address;
properties.cockpitHost = addressInfoCockpit.address;
properties.cockpitPort = addressInfoCockpit.port;
properties.logLevel = this.options.logLevel || "INFO";

const apiServer = new ApiServer({
config: config.getProperties(),
config: properties,
httpServerApi,
httpServerCockpit,
pluginRegistry,
Expand Down
48 changes: 48 additions & 0 deletions examples/supply-chain-app/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.git
*/*/node_modules
*/*/dist
*/*/build

.config.json
.nyc_output/
dist/
.DS_Store
node_modules/
docs/main
logs/
jspm_packages/
generated-sources/
coverage/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# next.js build output
.next

# vscode files
.vscode/*
!.vscode/template.launch.json

# Introperability App specifics
examples/simple-asset-transfer/fabric/**/hfc-key-store/

bin/
.tmp/
lerna-debug.log
cactus-openapi-spec.json
cactus-openapi-spec-*.json
.npmrc
*.log
139 changes: 139 additions & 0 deletions examples/supply-chain-app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
FROM node:12.20.1-alpine3.12 as builder

RUN apk update

# Need JDK for the openapi-generator that is part of the build process
RUN apk add --no-cache openjdk8=8.252.09-r0

# Need git because some of our npm depedencies might be coming
# straight from github instead of being an npm package on npmjs.com.
RUN apk add --no-cache git

# Some install scripts of the npm package fabric-network need python
RUN apk add --no-cache python3 py3-pip

RUN npm install modclean -g

WORKDIR /
RUN mkdir /app/
WORKDIR /app/
COPY ./ ./
RUN npm ci
RUN ./node_modules/.bin/lerna clean --yes
RUN ./node_modules/.bin/lerna bootstrap
RUN npm run build:dev:backend
RUN npm run webpack:dev:web
RUN npm run build:dev:frontend -- --scope='@hyperledger/cactus-example-supply-chain-frontend'
RUN ./node_modules/.bin/lerna clean --yes
RUN ./node_modules/.bin/lerna bootstrap -- --production --no-optional

# RUN modclean --run --patterns="default:*" --path ./examples/cactus-example-supply-chain-backend/
# RUN modclean --run --patterns="default:*" --path ./examples/cactus-example-supply-chain-business-logic-plugin/
# RUN modclean --run --patterns="default:*" --path ./examples/cactus-example-supply-chain-frontend/
# RUN modclean --run --patterns="default:*" --path ./packages/cactus-api-client/
# RUN modclean --run --patterns="default:*" --path ./packages/cactus-cmd-api-server/
# RUN modclean --run --patterns="default:*" --path ./packages/cactus-cockpit/
# RUN modclean --run --patterns="default:*" --path ./packages/cactus-common/
# RUN modclean --run --patterns="default:*" --path ./packages/cactus-core-api/
# RUN modclean --run --patterns="default:*" --path ./packages/cactus-core/
# RUN modclean --run --patterns="default:*" --path ./packages/cactus-plugin-consortium-manual/
# RUN modclean --run --patterns="default:*" --path ./packages/cactus-plugin-keychain-memory/
# RUN modclean --run --patterns="default:*" --path ./packages/cactus-plugin-keychain-vault/
# RUN modclean --run --patterns="default:*" --path ./packages/cactus-plugin-ledger-connector-besu/
# RUN modclean --run --patterns="default:*" --path ./packages/cactus-plugin-ledger-connector-fabric/
# RUN modclean --run --patterns="default:*" --path ./packages/cactus-plugin-ledger-connector-quorum/
# RUN modclean --run --patterns="default:*" --path ./packages/cactus-test-tooling/

RUN rm -rf ./packages/cactus-test-plugin*
RUN rm -rf ./packages/cactus-test-cmd*
RUN rm -rf ./packages/cactus-test-api*
RUN rm -rf ./node_modules/

FROM docker:20.10.2-dind-rootless as runner

USER root

RUN apk update

# Add bash for convenience, sh has less features
RUN apk add --no-cache bash=5.0.17-r0

# Need curl for healthchecks
RUN apk add --no-cache curl=7.69.1-r3

# The file binary is used to inspect exectubles when debugging container image issues
RUN apk add --no-cache file=5.38-r0

RUN apk add --no-cache nodejs=12.20.1-r0
RUN apk add --no-cache npm=12.20.1-r0

RUN apk add --no-cache ca-certificates=20191127-r4
RUN apk add --no-cache tzdata=2020f-r0

# Install supervisord because we need to run the docker daemon and also the fabric network
# meaning that we have multiple processes to run.
RUN apk add --no-cache supervisor=4.2.0-r0

ARG APP=/usr/src/app/

ENV TZ=Etc/UTC
ENV APP_USER=appuser

RUN addgroup --system $APP_USER
RUN adduser --system $APP_USER -G $APP_USER
RUN addgroup $APP_USER rootless
RUN mkdir -p ${APP}

COPY --chown=$APP_USER:$APP_USER --from=builder /app/ ${APP}

RUN mkdir -p "${APP}/log/"
RUN chown -R $APP_USER:$APP_USER "${APP}/log/"

# TODO: Can we hack it together so that the whole thing works rootless?
# USER $APP_USER

WORKDIR ${APP}

COPY --chown=${APP_USER}:${APP_USER} ./examples/supply-chain-app/healthcheck.sh /

ENV CACTUS_NODE_ID=-
ENV CONSORTIUM_ID=-
ENV KEY_PAIR_PEM=-
ENV COCKPIT_WWW_ROOT=examples/cactus-example-supply-chain-frontend/www/
ENV COCKPIT_TLS_ENABLED=false
ENV COCKPIT_CORS_DOMAIN_CSV=\*
ENV COCKPIT_MTLS_ENABLED=false
ENV COCKPIT_TLS_CERT_PEM=-
ENV COCKPIT_TLS_KEY_PEM=-
ENV COCKPIT_TLS_CLIENT_CA_PEM=-
ENV COCKPIT_HOST=0.0.0.0
ENV COCKPIT_PORT=3000
ENV API_MTLS_ENABLED=false
ENV API_TLS_ENABLED=false
ENV API_CORS_DOMAIN_CSV=\*
ENV API_TLS_CERT_PEM=-
ENV API_TLS_CLIENT_CA_PEM=-
ENV API_TLS_KEY_PEM=-
ENV API_HOST=0.0.0.0
ENV API_PORT=4000
ENV LOG_LEVEL=TRACE

COPY examples/supply-chain-app/supervisord.conf /etc/supervisord.conf

# supervisord web ui/dashboard
EXPOSE 9001
# API #1
EXPOSE 4000
# API #2
EXPOSE 4100
# GUI #1
EXPOSE 3000
# GUI #2
EXPOSE 3100

# Extend the parent image's entrypoint
# https://superuser.com/questions/1459466/can-i-add-an-additional-docker-entrypoint-script
ENTRYPOINT ["/usr/bin/supervisord"]
CMD ["--configuration", "/etc/supervisord.conf", "--nodaemon"]
HEALTHCHECK --interval=1s --timeout=5s --start-period=20s --retries=250 \
CMD /usr/src/app/examples/supply-chain-app/healthcheck.sh
Loading

0 comments on commit 2b2c32c

Please sign in to comment.