From 82b1249f4e5cf4998037527300db8b67a874bcaf Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 18 Aug 2021 17:01:04 +0100 Subject: [PATCH] Improve Docker support - default command should be start, rather than start:dev in the docker image - added a multistage build - fixed node-gyp error - removed dev dependencies - added a start:dotenv script to support a .env file in production (may be useful for k8s later) - updated Readme and generateEnv script to simplify the setup - updated external network in docker-compose.yaml to match the test network Signed-off-by: James Taylor --- README.md | 41 ++++++++++--------- .../rest-api-typescript/.env.sample | 15 ++++--- .../rest-api-typescript/Dockerfile | 27 +++++++----- .../rest-api-typescript/docker-compose.yaml | 12 +++--- .../rest-api-typescript/package.json | 1 + .../scripts/generateEnv.sh | 40 ++++++++++++++---- 6 files changed, 85 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index b5f40edf..06f58ab8 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,28 @@ Start the sample REST server npm run start:dev ``` +### Docker image + +Alternatively, run the following commands in the `fabric-rest-sample/asset-transfer-basic/rest-api-typescript` directory to start the sample in a Docker container + +Build the Docker image + +```shell +docker build -t fabric-rest-sample . +``` + +Create a `.env` file to configure the server for the test network (make sure `TEST_NETWORK_HOME` is set to the fully qualified `test-network` directory and `AS_LOCAL_HOST` is set to `false` so that the server works inside the Docker Compose network) + +```shell +TEST_NETWORK_HOME=$HOME/fabric-samples/test-network AS_LOCAL_HOST=false npm run generateEnv +``` + +Start the sample REST server and Redis server + +```shell +docker-compose up -d +``` + ## REST API If everything went well, you can now make basic asset transfer REST calls! @@ -105,22 +127,3 @@ curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${ ```shell curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request DELETE http://localhost:3000/api/assets/asset7 ``` -## Steps to run the application using docker: - -Move to directory fabric-rest-sample/asset-transfer-basic/rest-api-typescript - -### Build docker image - docker build -t fabricapp . - -### Generate .env file - TEST_NETWORK_HOME=$HOME/fabric-samples/test-network ./scripts/generateEnv.sh - - Note: Connection profile need to use the peer container’s hostname instead of localhost. - -### Run docker containers - docker-compose up -d - - - - - diff --git a/asset-transfer-basic/rest-api-typescript/.env.sample b/asset-transfer-basic/rest-api-typescript/.env.sample index f81d0dcf..dc052b68 100644 --- a/asset-transfer-basic/rest-api-typescript/.env.sample +++ b/asset-transfer-basic/rest-api-typescript/.env.sample @@ -4,6 +4,10 @@ PORT=3000 RETRY_DELAY=3000 +MAX_RETRY_COUNT=5 + +AS_LOCAL_HOST=true + HLF_CONNECTION_PROFILE_ORG1={"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... } HLF_CERTIFICATE_ORG1="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n" @@ -16,19 +20,20 @@ HLF_CERTIFICATE_ORG2="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE---- HLF_PRIVATE_KEY_ORG2="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n" - HLF_COMMIT_TIMEOUT=3000 HLF_ENDORSE_TIMEOUT=30 +HLF_QUERY_TIMEOUT=3 + REDIS_HOST=localhost REDIS_PORT=6379 -ORG1_APIKEY=D2F66BFF-D68B-458D-8FA6-285F172D5B03 - -ORG2_APIKEY=92042C1F-8E58-48F9-9EAF-91A98A2B7648 - #REDIS_USERNAME= #REDIS_PASSWORD= + +ORG1_APIKEY=D2F66BFF-D68B-458D-8FA6-285F172D5B03 + +ORG2_APIKEY=92042C1F-8E58-48F9-9EAF-91A98A2B764 diff --git a/asset-transfer-basic/rest-api-typescript/Dockerfile b/asset-transfer-basic/rest-api-typescript/Dockerfile index 5ebc77bd..073c68f1 100644 --- a/asset-transfer-basic/rest-api-typescript/Dockerfile +++ b/asset-transfer-basic/rest-api-typescript/Dockerfile @@ -1,20 +1,25 @@ -FROM node:14-alpine3.12 -RUN apk add dumb-init -WORKDIR /fabric_app/ +FROM node:14-alpine3.12 AS build -COPY --chown=node:node . /fabric_app/ +RUN apk add --no-cache g++ make python3 dumb-init -RUN npm ci +WORKDIR /app +COPY --chown=node:node . /app + +RUN npm ci RUN npm run build +RUN npm prune --production + +FROM node:14-alpine3.12 +ENV NODE_ENV production +WORKDIR /app + +COPY --from=build /usr/bin/dumb-init /usr/bin/dumb-init +COPY --chown=node:node --from=build /app . EXPOSE 3000 USER node -CMD dumb-init npm run start:dev - - - - - +ENTRYPOINT [ "dumb-init", "--", "npm", "run"] +CMD ["start"] diff --git a/asset-transfer-basic/rest-api-typescript/docker-compose.yaml b/asset-transfer-basic/rest-api-typescript/docker-compose.yaml index 1a2c7b93..b7c4b0b3 100644 --- a/asset-transfer-basic/rest-api-typescript/docker-compose.yaml +++ b/asset-transfer-basic/rest-api-typescript/docker-compose.yaml @@ -6,21 +6,19 @@ services: ports: - 6379:6379 networks: - - net_test + - fabric_test nodeapp: - image: 'fabricapp' + image: 'fabric-rest-sample' + command: ['start:dotenv'] ports: - 3000:3000 env_file: - ./.env - environment: - - REDIS_HOST=redis - - AS_LOCAL_HOST=false networks: - - net_test + - fabric_test networks: - net_test: + fabric_test: external: true diff --git a/asset-transfer-basic/rest-api-typescript/package.json b/asset-transfer-basic/rest-api-typescript/package.json index 18919584..815f9e19 100644 --- a/asset-transfer-basic/rest-api-typescript/package.json +++ b/asset-transfer-basic/rest-api-typescript/package.json @@ -51,6 +51,7 @@ "generateEnv": "./scripts/generateEnv.sh", "lint": "eslint . --ext .ts", "start": "node --require source-map-support/register ./dist", + "start:dotenv": "node --require source-map-support/register --require dotenv/config ./dist", "start:dev": "node --require source-map-support/register --require dotenv/config ./dist | pino-pretty", "start:redis": "docker run -p 6379:6379 --name fabric-sample-redis -d redis", "test": "jest" diff --git a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh index 902397f8..c910651e 100755 --- a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh +++ b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh @@ -4,6 +4,8 @@ # SPDX-License-Identifier: Apache-2.0 # +${AS_LOCAL_HOST:=true} + : "${TEST_NETWORK_HOME:=../..}" : "${CONNECTION_PROFILE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/connection-org1.json}" : "${CERTIFICATE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem}" @@ -23,14 +25,10 @@ RETRY_DELAY=3000 MAX_RETRY_COUNT=5 -HLF_CONNECTION_PROFILE_ORG1=$(cat ${CONNECTION_PROFILE_FILE_ORG1} | jq -c .) - HLF_CERTIFICATE_ORG1="$(cat ${CERTIFICATE_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')" HLF_PRIVATE_KEY_ORG1="$(cat ${PRIVATE_KEY_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')" -HLF_CONNECTION_PROFILE_ORG2=$(cat ${CONNECTION_PROFILE_FILE_ORG2} | jq -c .) - HLF_CERTIFICATE_ORG2="$(cat ${CERTIFICATE_FILE_ORG2} | sed -e 's/$/\\n/' | tr -d '\r\n')" HLF_PRIVATE_KEY_ORG2="$(cat ${PRIVATE_KEY_FILE_ORG2} | sed -e 's/$/\\n/' | tr -d '\r\n')" @@ -39,7 +37,7 @@ HLF_COMMIT_TIMEOUT=3000 HLF_ENDORSE_TIMEOUT=30 -REDIS_HOST=localhost +HLF_QUERY_TIMEOUT=3 REDIS_PORT=6379 @@ -47,8 +45,32 @@ ORG1_APIKEY=$(uuidgen) ORG2_APIKEY=$(uuidgen) -#REDIS_USERNAME= - -#REDIS_PASSWORD= - ENV_END + +if [ "${AS_LOCAL_HOST}" = "true" ]; then + +cat << LOCAL_HOST_END >> .env +AS_LOCAL_HOST=true + +HLF_CONNECTION_PROFILE_ORG1=$(cat ${CONNECTION_PROFILE_FILE_ORG1} | jq -c .) + +HLF_CONNECTION_PROFILE_ORG2=$(cat ${CONNECTION_PROFILE_FILE_ORG2} | jq -c .) + +REDIS_HOST=localhost + +LOCAL_HOST_END + +elif [ "${AS_LOCAL_HOST}" = "false" ]; then + +cat << WITH_HOSTNAME_END >> .env +AS_LOCAL_HOST=false + +HLF_CONNECTION_PROFILE_ORG1=$(cat ${CONNECTION_PROFILE_FILE_ORG1} | jq -c '.peers["peer0.org1.example.com"].url = "grpcs://peer0.org1.example.com:7051" | .certificateAuthorities["ca.org1.example.com"].url = "https://ca.org1.example.com:7054"') + +HLF_CONNECTION_PROFILE_ORG2=$(cat ${CONNECTION_PROFILE_FILE_ORG2} | jq -c '.peers["peer0.org2.example.com"].url = "grpcs://peer0.org2.example.com:9051" | .certificateAuthorities["ca.org2.example.com"].url = "https://ca.org2.example.com:8054"') + +REDIS_HOST=redis + +WITH_HOSTNAME_END + +fi