├── .github └── workflows │ ├── game-2048-kubescape.yaml │ ├── game-2048-snyk.yaml │ ├── online-boutique-main-ci.yaml │ ├── online-boutique-pr-ci.yaml │ ├── online-boutique-pr-kustomize-validation.yaml │ ├── online-boutique-release.yaml │ ├── online-boutique-snyk-docker-scan.yaml │ ├── online-boutique-snyk-iac-scan.yaml │ └── online-boutique-snyk-source-code-scan.yaml ├── .gitignore ├── README.md ├── bookinfo-example ├── README.md ├── assets │ └── images │ │ └── product-page-welcome.png └── kustomize │ ├── kustomization.yaml │ └── resources │ └── namespace.yaml ├── doks-example ├── .travis.yml ├── Dockerfile ├── LICENSE ├── README.md ├── manifest.yaml ├── script │ ├── docker-publish │ ├── down │ ├── up │ └── wait-for-service └── web │ ├── bg.png │ ├── do.png │ ├── index.html │ └── style.css ├── emojivoto-example ├── README.md ├── assets │ └── images │ │ └── emojivoto-welcome-page.png └── kustomize │ ├── kustomization.yaml │ └── patches │ ├── emoji-svc.yaml │ └── voting-svc.yaml ├── game-2048-example ├── .dockerignore ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── Tiltfile ├── assets │ └── images │ │ └── game-2048-welcome-page.png ├── knative-service.yaml ├── kustomize │ ├── kustomization.yaml │ └── resources │ │ ├── deployment.yaml │ │ ├── namespace.yaml │ │ └── service.yaml ├── package-lock.json ├── package.json ├── src │ └── index.js └── webpack.config.js ├── microservices-demo ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── Tiltfile ├── kustomize │ ├── base │ │ ├── cartservice.yaml │ │ ├── checkoutservice.yaml │ │ ├── currencyservice.yaml │ │ ├── emailservice.yaml │ │ ├── frontend.yaml │ │ ├── kustomization.yaml │ │ ├── namespace.yaml │ │ ├── paymentservice.yaml │ │ ├── productcatalogservice.yaml │ │ ├── recommendationservice.yaml │ │ ├── redis.yaml │ │ └── shippingservice.yaml │ ├── dev │ │ └── kustomization.yaml │ ├── kustomization.yaml │ ├── prod │ │ └── kustomization.yaml │ └── staging │ │ └── kustomization.yaml ├── release-scripts │ ├── README.md │ ├── license_header.txt │ ├── make-cnb-docker-images.sh │ ├── make-docker-images.sh │ ├── make-release-artifacts.sh │ └── make-release.sh ├── src │ ├── .gitignore │ ├── cartservice │ │ ├── .gitignore │ │ ├── cartservice.sln │ │ ├── src │ │ │ ├── .dockerignore │ │ │ ├── Dockerfile │ │ │ ├── Dockerfile.debug │ │ │ ├── Program.cs │ │ │ ├── Startup.cs │ │ │ ├── appsettings.json │ │ │ ├── cartservice.csproj │ │ │ ├── cartstore │ │ │ │ ├── ICartStore.cs │ │ │ │ └── RedisCartStore.cs │ │ │ ├── protos │ │ │ │ └── Cart.proto │ │ │ └── services │ │ │ │ ├── CartService.cs │ │ │ │ └── HealthCheckService.cs │ │ └── tests │ │ │ ├── .gitignore │ │ │ ├── CartServiceTests.cs │ │ │ └── cartservice.tests.csproj │ ├── checkoutservice │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── genproto.sh │ │ ├── genproto │ │ │ └── demo.pb.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ └── money │ │ │ ├── money.go │ │ │ └── money_test.go │ ├── currencyservice │ │ ├── .dockerignore │ │ ├── .gitignore │ │ ├── Dockerfile │ │ ├── client.js │ │ ├── data │ │ │ └── currency_conversion.json │ │ ├── genproto.sh │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── proto │ │ │ ├── demo.proto │ │ │ └── grpc │ │ │ │ └── health │ │ │ │ └── v1 │ │ │ │ └── health.proto │ │ └── server.js │ ├── emailservice │ │ ├── .python-version │ │ ├── Dockerfile │ │ ├── Procfile │ │ ├── demo_pb2.py │ │ ├── demo_pb2_grpc.py │ │ ├── email_client.py │ │ ├── email_server.py │ │ ├── genproto.sh │ │ ├── logger.py │ │ ├── pytest.ini │ │ ├── requirements.in │ │ ├── requirements.txt │ │ ├── templates │ │ │ └── confirmation.html │ │ └── tests │ │ │ └── test_sample.py │ ├── frontend │ │ ├── .dockerignore │ │ ├── .gitkeep │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── deployment_details.go │ │ ├── genproto.sh │ │ ├── genproto │ │ │ └── demo.pb.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── handlers.go │ │ ├── main.go │ │ ├── middleware.go │ │ ├── money │ │ │ ├── money.go │ │ │ └── money_test.go │ │ ├── rpc.go │ │ ├── static │ │ │ ├── favicon-cymbal.ico │ │ │ ├── favicon.ico │ │ │ ├── icons │ │ │ │ ├── Cymbal_NavLogo.svg │ │ │ │ ├── Hipster_Advert2.svg │ │ │ │ ├── Hipster_CartIcon.svg │ │ │ │ ├── Hipster_CheckOutIcon.svg │ │ │ │ ├── Hipster_CurrencyIcon.svg │ │ │ │ ├── Hipster_DownArrow.svg │ │ │ │ ├── Hipster_FacebookIcon.svg │ │ │ │ ├── Hipster_GooglePlayIcon.svg │ │ │ │ ├── Hipster_HelpIcon.svg │ │ │ │ ├── Hipster_HeroLogo.svg │ │ │ │ ├── Hipster_HeroLogoCyan.svg │ │ │ │ ├── Hipster_InstagramIcon.svg │ │ │ │ ├── Hipster_KitchenwareOffer.svg │ │ │ │ ├── Hipster_NavLogo.svg │ │ │ │ ├── Hipster_PinterestIcon.svg │ │ │ │ ├── Hipster_ProfileIcon.svg │ │ │ │ ├── Hipster_SearchIcon.svg │ │ │ │ ├── Hipster_TwitterIcon.svg │ │ │ │ ├── Hipster_UpDownControl.svg │ │ │ │ └── Hipster_YoutubeIcon.svg │ │ │ ├── images │ │ │ │ ├── Advert2BannerImage.png │ │ │ │ ├── AdvertBannerImage.png │ │ │ │ ├── HeroBannerImage.png │ │ │ │ ├── HeroBannerImage2.png │ │ │ │ ├── VRHeadsets.png │ │ │ │ ├── credits.txt │ │ │ │ ├── folded-clothes-on-white-chair-wide.jpg │ │ │ │ └── folded-clothes-on-white-chair.jpg │ │ │ ├── img │ │ │ │ └── products │ │ │ │ │ ├── bamboo-glass-jar.jpg │ │ │ │ │ ├── candle-holder.jpg │ │ │ │ │ ├── hairdryer.jpg │ │ │ │ │ ├── loafers.jpg │ │ │ │ │ ├── mug.jpg │ │ │ │ │ ├── salt-and-pepper-shakers.jpg │ │ │ │ │ ├── sunglasses.jpg │ │ │ │ │ ├── tank-top.jpg │ │ │ │ │ └── watch.jpg │ │ │ └── styles │ │ │ │ ├── cart.css │ │ │ │ ├── order.css │ │ │ │ └── styles.css │ │ └── templates │ │ │ ├── ad.html │ │ │ ├── cart.html │ │ │ ├── error.html │ │ │ ├── footer.html │ │ │ ├── header.html │ │ │ ├── home.html │ │ │ ├── order.html │ │ │ ├── product.html │ │ │ └── recommendations.html │ ├── loadgenerator │ │ ├── Dockerfile │ │ ├── loadgenerator.yaml │ │ ├── locustfile.py │ │ ├── requirements.in │ │ └── requirements.txt │ ├── paymentservice │ │ ├── .dockerignore │ │ ├── .gitignore │ │ ├── Dockerfile │ │ ├── charge.js │ │ ├── genproto.sh │ │ ├── index.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── proto │ │ │ ├── demo.proto │ │ │ └── grpc │ │ │ │ └── health │ │ │ │ └── v1 │ │ │ │ └── health.proto │ │ └── server.js │ ├── productcatalogservice │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── genproto.sh │ │ ├── genproto │ │ │ └── demo.pb.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── products.json │ │ ├── server.go │ │ └── server_test.go │ ├── recommendationservice │ │ ├── .gitignore │ │ ├── .python-version │ │ ├── Dockerfile │ │ ├── Procfile │ │ ├── client.py │ │ ├── demo_pb2.py │ │ ├── demo_pb2_grpc.py │ │ ├── genproto.sh │ │ ├── logger.py │ │ ├── pytest.ini │ │ ├── recommendation_server.py │ │ ├── requirements.in │ │ ├── requirements.txt │ │ └── tests │ │ │ └── test_sample.py │ └── shippingservice │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── genproto.sh │ │ ├── genproto │ │ └── demo.pb.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ ├── quote.go │ │ ├── shippingservice_test.go │ │ └── tracker.go └── tilt-resources │ ├── dev │ └── tilt_config.json │ └── local │ └── tilt_config.json └── podinfo-example ├── README.md ├── assets └── images │ └── podinfo-welcome-page.png └── kustomize ├── kustomization.yaml └── resources └── namespace.yaml /.github/workflows/online-boutique-pr-kustomize-validation.yaml: -------------------------------------------------------------------------------- 1 | name: Online Boutique PR Kustomize Validation 2 | 3 | on: 4 | workflow_dispatch: 5 | # pull_request: 6 | # branches: 7 | # - main 8 | # paths: 9 | # - "kustomize/**" 10 | 11 | env: 12 | KUBECONFORM_VERSION: "0.5.0" 13 | KUBERNETES_VERSION: "1.24.4" 14 | 15 | jobs: 16 | job: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout code 20 | uses: actions/checkout@v3 21 | 22 | - name: Set up kubeconform 23 | run: | 24 | ( 25 | cd /tmp 26 | wget "https://github.com/yannh/kubeconform/releases/download/v${{ env.KUBECONFORM_VERSION }}/kubeconform-linux-amd64.tar.gz" 27 | tar xvf kubeconform-linux-amd64.tar.gz 28 | chmod u+x ./kubeconform 29 | ) 30 | 31 | - name: Kustomize linting using kubeconform 32 | run: | 33 | # Test each overlay using kubeconform 34 | for kustomize_overlay in kustomize/*/; do 35 | kustomize build "$kustomize_overlay" | \ 36 | /tmp/kubeconform -kubernetes-version "${{env.KUBERNETES_VERSION}}" -summary -verbose 37 | done 38 | -------------------------------------------------------------------------------- /.github/workflows/online-boutique-release.yaml: -------------------------------------------------------------------------------- 1 | name: Online Boutique Release 2 | 3 | on: 4 | workflow_dispatch: 5 | # push: 6 | # # Trigger on push events to any tag matching semantic versioning 7 | # tags: 8 | # - 'v[0-9]+\.[0-9]+\.[0-9]+' 9 | 10 | env: 11 | RELEASE_COMMIT_AUTHOR: "GitHub Release Actions" 12 | RELEASE_COMMIT_AUTHOR_EMAIL: "gh-release-actions@noreply.github.com" 13 | DOCR_ENDPOINT: "registry.digitalocean.com/microservices-demo" 14 | PROJECT_NAME: "online-boutique" 15 | 16 | jobs: 17 | validation-tests: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - run: echo "[INFO] Not implemented yet!" 21 | 22 | build-and-push-release-images: 23 | needs: validation-tests 24 | runs-on: ubuntu-latest 25 | strategy: 26 | matrix: 27 | project: 28 | - cartservice 29 | - checkoutservice 30 | - currencyservice 31 | - emailservice 32 | - frontend 33 | - paymentservice 34 | - productcatalogservice 35 | - recommendationservice 36 | - shippingservice 37 | steps: 38 | - name: Checkout code 39 | uses: actions/checkout@v3 40 | 41 | - name: Install doctl 42 | uses: digitalocean/action-doctl@v2 43 | with: 44 | token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} 45 | 46 | - name: Log in to DOCR with short-lived credentials 47 | run: doctl registry login --expiry-seconds 600 48 | 49 | - name: Build and push image 50 | uses: docker/build-push-action@v3 51 | with: 52 | # cartservice is an exception - Dockerfile is placed in src/cartservice/src subfolder 53 | context: "src/${{ matrix.project }}/${{ matrix.project == 'cartservice' && 'src' || ''}}" 54 | push: true 55 | tags: "${{ env.DOCR_ENDPOINT }}/${{ matrix.project }}:${{ github.ref_name }}" 56 | 57 | # Kustomize image field for each microservice present in the `src/` dir 58 | # Finally, commit changes to main branch and let ArgoCD take over afterwards 59 | apply-kustomize-changes: 60 | needs: build-and-push-release-images 61 | runs-on: ubuntu-latest 62 | steps: 63 | - name: Checkout code 64 | uses: actions/checkout@v3 65 | 66 | - name: Set up K8S tools 67 | uses: yokawasa/action-setup-kube-tools@v0.8.2 68 | with: 69 | kustomize: "4.5.7" 70 | 71 | - name: Kustomize staging environment images 72 | run: | 73 | for microservice in src/*/; do 74 | microservice="$(basename $microservice)" 75 | if [[ "$microservice" == "loadgenerator" ]]; then 76 | continue 77 | fi 78 | ( 79 | cd kustomize/staging/ 80 | kustomize edit set image $microservice=${{ env.DOCR_ENDPOINT }}/${microservice}:${{ github.ref_name }} 81 | ) 82 | done 83 | 84 | - name: Commit Kustomize manifests for staging env 85 | run: | 86 | git config --global user.name "${{ env.RELEASE_COMMIT_AUTHOR }}" 87 | git config --global user.email "${{ env.RELEASE_COMMIT_AUTHOR_EMAIL }}" 88 | git add kustomize/staging/ 89 | git commit -m "[Release] Bump docker images tag to ${{ github.ref_name }}" 90 | 91 | - name: Push changes 92 | uses: ad-m/github-push-action@master 93 | with: 94 | github_token: ${{ secrets.GITHUB_TOKEN }} 95 | 96 | -------------------------------------------------------------------------------- /.github/workflows/online-boutique-snyk-docker-scan.yaml: -------------------------------------------------------------------------------- 1 | name: Online Boutique Snyk Docker Scan 2 | 3 | on: 4 | # pull_request: 5 | # branches: 6 | # - main 7 | # paths: 8 | # - "src/**/Dockerfile" 9 | 10 | # Below configuration is used for manual workflow dispatch 11 | workflow_dispatch: 12 | inputs: 13 | snyk_fail_threshold: 14 | description: | 15 | Sets fail threshold for Snyk 16 | (low | medium | high | critical) 17 | required: true 18 | default: "high" 19 | 20 | env: 21 | DOCR_ENDPOINT: "registry.digitalocean.com/microservices-demo" 22 | PROJECT_NAME: "online-boutique" 23 | SNYK_FAIL_THRESHOLD: "high" 24 | 25 | jobs: 26 | container-security-check: 27 | runs-on: ubuntu-latest 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | project: 32 | - cartservice 33 | - checkoutservice 34 | - currencyservice 35 | - emailservice 36 | - frontend 37 | - paymentservice 38 | - productcatalogservice 39 | - recommendationservice 40 | - shippingservice 41 | steps: 42 | - name: Checkout 43 | uses: actions/checkout@v3 44 | with: 45 | ref: ${{ github.event.pull_request.head.ref }} 46 | repository: ${{ github.event.pull_request.head.repo.full_name }} 47 | 48 | - name: Install Snyk 49 | uses: snyk/actions/setup@master 50 | 51 | - name: Build app image for Snyk container scanning 52 | uses: docker/build-push-action@v3 53 | with: 54 | # Cartservice is an exception - Dockerfile is placed in `src/cartservice/src` subfolder 55 | context: "src/${{ matrix.project }}/${{ matrix.project == 'cartservice' && 'src' || ''}}" 56 | push: false 57 | tags: "${{ env.DOCR_ENDPOINT }}/${{ matrix.project }}:${{ github.event.pull_request.head.sha }}" 58 | 59 | - name: Check application container vulnerabilities 60 | run: | 61 | # Cartservice is an exception regarding project layout 62 | # It uses a nested src subfolder - `src/cartservice/src` 63 | if [[ "${{ matrix.project }}" == "cartservice" ]]; then 64 | cd src/ 65 | fi 66 | snyk container test "${{ env.DOCR_ENDPOINT }}/${{ matrix.project }}:${{ github.event.pull_request.head.sha }}" \ 67 | --file=Dockerfile \ 68 | --severity-threshold=${{ github.event.inputs.snyk_fail_threshold || env.SNYK_FAIL_THRESHOLD }} \ 69 | --target-name=${{ env.PROJECT_NAME }} \ 70 | --target-reference=${{ matrix.project }} 71 | env: 72 | SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} 73 | working-directory: "src/${{ matrix.project }}" 74 | -------------------------------------------------------------------------------- /.github/workflows/online-boutique-snyk-iac-scan.yaml: -------------------------------------------------------------------------------- 1 | name: Online Boutique Snyk IAC Scan 2 | 3 | on: 4 | # pull_request: 5 | # branches: 6 | # - main 7 | # paths: 8 | # - "argocd/**" 9 | # - "kustomize/**" 10 | 11 | # Below configuration is used for manual workflow dispatch 12 | workflow_dispatch: 13 | inputs: 14 | snyk_fail_threshold: 15 | description: | 16 | Sets fail threshold for Snyk 17 | (low | medium | high | critical) 18 | required: true 19 | default: "high" 20 | 21 | env: 22 | PROJECT_NAME: "online-boutique" 23 | SNYK_FAIL_THRESHOLD: "high" 24 | 25 | jobs: 26 | iac-security-check: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v3 31 | with: 32 | ref: ${{ github.event.pull_request.head.ref }} 33 | repository: ${{ github.event.pull_request.head.repo.full_name }} 34 | 35 | - name: Install Snyk 36 | uses: snyk/actions/setup@master 37 | 38 | - name: Check for Kubernetes manifests vulnerabilities 39 | run: | 40 | snyk iac test \ 41 | --severity-threshold=${{ github.event.inputs.snyk_fail_threshold || env.SNYK_FAIL_THRESHOLD }} \ 42 | --target-name=${{ env.PROJECT_NAME }} \ 43 | --target-reference="kustomize-PR#${{ github.event.pull_request.number }}" \ 44 | --report 45 | env: 46 | SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} 47 | working-directory: kustomize 48 | 49 | - name: Check for Argo CD manifests vulnerabilities 50 | run: | 51 | snyk iac test \ 52 | --severity-threshold=${{ github.event.inputs.snyk_fail_threshold || env.SNYK_FAIL_THRESHOLD }} \ 53 | --target-name=${{ env.PROJECT_NAME }} \ 54 | --target-reference="argocd-PR#${{ github.event.pull_request.number }}" \ 55 | --report 56 | env: 57 | SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} 58 | working-directory: argocd 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DigitalOcean Kubernetes Sample Apps 2 | 3 | This repository contains a collection of Kubernetes applications that can be used in various projects. Each sample application has a dedicated folder to keep all resources, and main documentation. 4 | 5 | Kubernetes sample applications provided by this repository: 6 | 7 | - [bookinfo-example](bookinfo-example/) - Deploy the [Bookinfo](https://istio.io/latest/docs/examples/bookinfo) sample application. 8 | - [doks-example](doks-example/) - Deploy your first application (workload) to a fresh DOKS cluster. 9 | - [emojivoto-example](emojivoto-example/) - Deploy the [Emojivoto](https://github.com/BuoyantIO/emojivoto) sample application. 10 | - [game-2048-example](game-2048-example/) - Build and deploy the [2048 game](https://en.wikipedia.org/wiki/2048_(video_game)) application. 11 | - [podinfo-example](podinfo-example/) - Deploy the [Podinfo](https://github.com/stefanprodan/podinfo) sample application. 12 | -------------------------------------------------------------------------------- /bookinfo-example/assets/images/product-page-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/bookinfo-example/assets/images/product-page-welcome.png -------------------------------------------------------------------------------- /bookinfo-example/kustomize/kustomization.yaml: -------------------------------------------------------------------------------- 1 | ## Bookinfo Sample Application Kustomization 2 | 3 | apiVersion: kustomize.config.k8s.io/v1beta1 4 | kind: Kustomization 5 | 6 | # Making sure all resources used in this tutorial are created in a dedicated namespace 7 | # Also specific annotations are added for later identification 8 | namespace: bookinfo 9 | commonAnnotations: 10 | provider: kubernetes-sample-apps 11 | 12 | # Bookinfo resources (namespace, services, deployments, etc) 13 | resources: 14 | - resources/namespace.yaml 15 | - https://raw.githubusercontent.com/istio/istio/release-1.14/samples/bookinfo/platform/kube/bookinfo.yaml 16 | # If you want to apply Istio configuration on top of the bookinfo deployment, uncomment below lines (assuming you have Istio already installed) 17 | # - https://raw.githubusercontent.com/istio/istio/release-1.14/samples/bookinfo/networking/bookinfo-gateway.yaml 18 | # - https://raw.githubusercontent.com/istio/istio/release-1.14/samples/bookinfo/networking/destination-rule-all.yaml 19 | -------------------------------------------------------------------------------- /bookinfo-example/kustomize/resources/namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: bookinfo 5 | -------------------------------------------------------------------------------- /doks-example/.travis.yml: -------------------------------------------------------------------------------- 1 | services: 2 | - 'docker' 3 | 4 | script: 5 | - docker build -t doks-example . 6 | - docker run --rm -it doks-example sleep 1 7 | 8 | notifications: 9 | email: false -------------------------------------------------------------------------------- /doks-example/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | 3 | ADD web /usr/share/nginx/html -------------------------------------------------------------------------------- /doks-example/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 DigitalOcean 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /doks-example/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/digitalocean/doks-example.svg?branch=master)](https://travis-ci.org/digitalocean/doks-example) 2 | 3 | # Getting Started 4 | 5 | 1. Create your Kubernetes cluster: `doctl k8s cluster create example` 6 | 1. Check that your cluster is available: `kubectl --context do-nyc1-example get nodes` 7 | 1. Deploy a workload to your cluster: `kubectl --context do-nyc1-example apply -f manifest.yaml` 8 | 1. Wait for the service to be ready: `script/wait-for-service do-nyc1-example doks-example` 9 | 1. Open the returned IP address in your browser, or run `open http://$(kubectl --context do-nyc1-example get service doks-example --template="{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}")` 10 | 11 | Or you can just run `script/up` to do all of this. 12 | 13 | ## Cleaning up 14 | 15 | Run `script/down` to tear down the cluster and remove the load-balancer. 16 | 17 | **Note:** If you delete the cluster directly, the load-balancer will stick around and result in charges. 18 | -------------------------------------------------------------------------------- /doks-example/manifest.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: doks-example 6 | spec: 7 | type: LoadBalancer 8 | selector: 9 | app: doks-example 10 | ports: 11 | - name: http 12 | protocol: TCP 13 | port: 80 14 | targetPort: 80 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: doks-example 20 | spec: 21 | replicas: 2 22 | selector: 23 | matchLabels: 24 | app: doks-example 25 | template: 26 | metadata: 27 | labels: 28 | app: doks-example 29 | spec: 30 | containers: 31 | - name: nginx 32 | image: digitalocean/doks-example 33 | ports: 34 | - containerPort: 80 35 | protocol: TCP 36 | -------------------------------------------------------------------------------- /doks-example/script/docker-publish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | TARGET="digitalocean/doks-example" 4 | docker build -t ${TARGET} . 5 | docker push ${TARGET} 6 | -------------------------------------------------------------------------------- /doks-example/script/down: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | CLUSTER="example" 4 | doctl compute load-balancer delete --force $(kubectl get svc doks-example -o jsonpath="{.metadata.annotations.kubernetes\.digitalocean\.com/load-balancer-id}") 5 | doctl k8s cluster delete ${CLUSTER} -------------------------------------------------------------------------------- /doks-example/script/up: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | CLUSTER="example" 4 | SERVICE="doks-example" 5 | CONTEXT="do-nyc1-${CLUSTER}" 6 | doctl k8s cluster create ${CLUSTER} 7 | kubectl --context ${CONTEXT} apply -f manifest.yaml 8 | script/wait-for-service ${CONTEXT} ${SERVICE} 9 | open http://$(kubectl --context ${CONTEXT} get service ${SERVICE} --template="{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}") -------------------------------------------------------------------------------- /doks-example/script/wait-for-service: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Pass the name of a service to check: sh wait-for-service.sh example 3 | set -euo pipefail 4 | EXTERNAL_IP="" 5 | CONTEXT="$1" 6 | SERVICE="$2" 7 | while [ -z $EXTERNAL_IP ]; do 8 | EXTERNAL_IP=$(kubectl --context ${CONTEXT} get service ${SERVICE} --template="{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}") 9 | if [ -z "${EXTERNAL_IP}" ]; then 10 | echo "Waiting for external IP..." 11 | sleep 10 12 | fi 13 | done 14 | echo "Ready: ${EXTERNAL_IP}" 15 | -------------------------------------------------------------------------------- /doks-example/web/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/doks-example/web/bg.png -------------------------------------------------------------------------------- /doks-example/web/do.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/doks-example/web/do.png -------------------------------------------------------------------------------- /doks-example/web/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | } 4 | 5 | body { 6 | margin: 0; 7 | padding: 25px; 8 | height: 100%; 9 | 10 | background-color: #0a1e99; 11 | background-image: url("/bg.png"); 12 | background-repeat: no-repeat; 13 | background-position: right bottom; 14 | background-size: 800px; 15 | } 16 | 17 | main { 18 | margin: auto; 19 | width: 900px; 20 | } 21 | 22 | h1, h2, h3 { 23 | color: white; 24 | } 25 | 26 | pre { 27 | border: 0; 28 | background-color: #031b4d; 29 | color: white; 30 | wdith: 100%; 31 | max-height: 400px; 32 | overflow: scroll; 33 | } 34 | 35 | .Header { 36 | opacity: 0.5; 37 | color: white; 38 | fill: white; 39 | } 40 | 41 | #welcome { 42 | color: white; 43 | } 44 | 45 | #welcome span.bui-u-textCode { 46 | background-color: #031b4d; 47 | border: 0; 48 | } 49 | 50 | #running { 51 | color: white; 52 | } 53 | 54 | #more { 55 | margin-top: 30px; 56 | font-size: 80%; 57 | } 58 | 59 | .more-item { 60 | padding: 20px; 61 | background-color: white; 62 | border-radius: 5px; 63 | } 64 | 65 | .more-item h3 { 66 | padding: 0; 67 | margin: 10px 0 10px 0; 68 | } 69 | 70 | .more-type { 71 | text-transform: uppercase; 72 | font-size: 80%; 73 | } 74 | 75 | #footer { 76 | background-color: transparent; 77 | color: white; 78 | font-size: 60%; 79 | } 80 | 81 | #footer a, #footer a:hover { 82 | color: white; 83 | } 84 | -------------------------------------------------------------------------------- /emojivoto-example/assets/images/emojivoto-welcome-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/emojivoto-example/assets/images/emojivoto-welcome-page.png -------------------------------------------------------------------------------- /emojivoto-example/kustomize/kustomization.yaml: -------------------------------------------------------------------------------- 1 | ## Emojivoto Sample Application Kustomization 2 | 3 | apiVersion: kustomize.config.k8s.io/v1beta1 4 | kind: Kustomization 5 | 6 | # Making sure all resources used in this tutorial are created in a dedicated namespace 7 | # Also specific annotations are added for later identification 8 | namespace: emojivoto 9 | commonAnnotations: 10 | provider: kubernetes-sample-apps 11 | 12 | # Emojivoto resources (namespace, services, deployments, etc) 13 | resources: 14 | - github.com/BuoyantIO/emojivoto/kustomize/deployment 15 | 16 | patches: 17 | - path: patches/emoji-svc.yaml 18 | target: 19 | version: v1 20 | kind: Service 21 | name: emoji-svc 22 | - path: patches/voting-svc.yaml 23 | target: 24 | version: v1 25 | kind: Service 26 | name: voting-svc 27 | -------------------------------------------------------------------------------- /emojivoto-example/kustomize/patches/emoji-svc.yaml: -------------------------------------------------------------------------------- 1 | - op: add 2 | path: /metadata/labels 3 | value: 4 | app: emoji-svc 5 | -------------------------------------------------------------------------------- /emojivoto-example/kustomize/patches/voting-svc.yaml: -------------------------------------------------------------------------------- 1 | - op: add 2 | path: /metadata/labels 3 | value: 4 | app: voting-svc 5 | -------------------------------------------------------------------------------- /game-2048-example/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/charts 15 | **/docker-compose* 16 | **/compose* 17 | **/Dockerfile* 18 | **/node_modules 19 | **/npm-debug.log 20 | **/obj 21 | **/secrets.dev.yaml 22 | **/values.dev.yaml 23 | README.md 24 | -------------------------------------------------------------------------------- /game-2048-example/.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/dist 3 | -------------------------------------------------------------------------------- /game-2048-example/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16-slim AS builder 2 | WORKDIR /usr/src/app 3 | COPY . . 4 | RUN npm install --include=dev 5 | # 6 | # Build mode can be set via NODE_ENV environment variable (development or production) 7 | # See project package.json and webpack.config.js 8 | # 9 | ENV NODE_ENV=development 10 | RUN npm run build 11 | 12 | FROM node:16-slim 13 | RUN npm install http-server -g 14 | RUN mkdir /public 15 | WORKDIR /public 16 | COPY --from=builder /usr/src/app/dist/ ./ 17 | EXPOSE 8080 18 | USER 1000 19 | CMD ["http-server"] 20 | -------------------------------------------------------------------------------- /game-2048-example/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 DigitalOcean 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /game-2048-example/Tiltfile: -------------------------------------------------------------------------------- 1 | os.putenv('DOCKER_DEFAULT_PLATFORM', 'linux/amd64') 2 | 3 | k8s_yaml(kustomize('kustomize')) 4 | 5 | docker_build('game-2048', '.') 6 | 7 | k8s_resource('game-2048', port_forwards='8080') 8 | -------------------------------------------------------------------------------- /game-2048-example/assets/images/game-2048-welcome-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/game-2048-example/assets/images/game-2048-welcome-page.png -------------------------------------------------------------------------------- /game-2048-example/knative-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: serving.knative.dev/v1 2 | kind: Service 3 | metadata: 4 | name: game-2048 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | # Replace with your docker registry info 10 | - image: registry.digitalocean.com//2048-game:latest 11 | ports: 12 | - containerPort: 80 13 | -------------------------------------------------------------------------------- /game-2048-example/kustomize/kustomization.yaml: -------------------------------------------------------------------------------- 1 | ## 2048 Game Sample Application Kustomization 2 | 3 | apiVersion: kustomize.config.k8s.io/v1beta1 4 | kind: Kustomization 5 | 6 | # Making sure all resources used in this tutorial are created in a dedicated namespace 7 | # Also specific annotations are added for later identification 8 | namespace: game-2048 9 | commonAnnotations: 10 | provider: kubernetes-sample-apps 11 | 12 | # 2048 game resources (namespace, services, deployments, etc) 13 | resources: 14 | - resources/namespace.yaml 15 | - resources/deployment.yaml 16 | - resources/service.yaml 17 | -------------------------------------------------------------------------------- /game-2048-example/kustomize/resources/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: game-2048 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: game-2048 11 | strategy: 12 | type: RollingUpdate 13 | template: 14 | metadata: 15 | labels: 16 | app: game-2048 17 | spec: 18 | containers: 19 | - name: backend 20 | # Replace the `<>` placeholders with your docker registry info 21 | image: registry.digitalocean.com//2048-game:latest 22 | ports: 23 | - name: http 24 | containerPort: 8080 25 | resources: 26 | requests: 27 | cpu: 200m 28 | memory: 100Mi 29 | limits: 30 | cpu: 300m 31 | memory: 200Mi 32 | # securityContext: 33 | # readOnlyRootFilesystem: true 34 | # runAsNonRoot: true 35 | # allowPrivilegeEscalation: false 36 | # capabilities: 37 | # drop: 38 | # - all 39 | -------------------------------------------------------------------------------- /game-2048-example/kustomize/resources/namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: game-2048 5 | -------------------------------------------------------------------------------- /game-2048-example/kustomize/resources/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: game-2048 5 | spec: 6 | ports: 7 | - name: http 8 | port: 8080 9 | targetPort: 8080 10 | selector: 11 | app: game-2048 12 | -------------------------------------------------------------------------------- /game-2048-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "knative-example", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "webpack server --config webpack.config.js --mode development", 7 | "build": "webpack", 8 | "build-dev": "webpack --mode development", 9 | "build-prod": "webpack --mode production", 10 | "test": "echo '=== DUMMY TEST ==='" 11 | }, 12 | "dependencies": { 13 | "game-2048": "^0.0.7" 14 | }, 15 | "devDependencies": { 16 | "css-loader": "^6.7.1", 17 | "html-webpack-plugin": "^5.5.0", 18 | "style-loader": "^3.3.1", 19 | "webpack": "^5.72.1", 20 | "webpack-cli": "^4.9.2", 21 | "webpack-dev-server": "^4.9.0" 22 | }, 23 | "author": "", 24 | "license": "MIT", 25 | "description": "Sample 2048 Game App" 26 | } 27 | -------------------------------------------------------------------------------- /game-2048-example/src/index.js: -------------------------------------------------------------------------------- 1 | import 'game-2048/style/main.css'; 2 | import Game from 'game-2048'; 3 | 4 | var gameContainerDiv = document.createElement('div'); 5 | gameContainerDiv.setAttribute('id', 'game-container'); 6 | gameContainerDiv.className = 'container'; 7 | document.body.appendChild(gameContainerDiv); 8 | 9 | const game = new Game({ 10 | gameContainer: gameContainerDiv 11 | }); 12 | -------------------------------------------------------------------------------- /game-2048-example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin') 3 | 4 | module.exports = { 5 | mode: process.env.NODE_ENV || 'none', 6 | module: { 7 | rules: [ 8 | { 9 | test: /\.css$/i, 10 | use: ["style-loader", "css-loader"], 11 | }, 12 | ], 13 | }, 14 | entry: './src/index.js', 15 | output: { 16 | filename: 'lib/bundle.js', 17 | path: path.resolve(__dirname, 'dist'), 18 | clean: true, 19 | }, 20 | plugins: [ 21 | new HtmlWebpackPlugin({ 22 | title: '2048 Game', 23 | }) 24 | ], 25 | devServer: { 26 | static: { 27 | directory: path.join(__dirname, 'dist'), 28 | }, 29 | compress: true, 30 | port: 8080, 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /microservices-demo/.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | 4 | # Tilt settings 5 | /tilt_config.json 6 | -------------------------------------------------------------------------------- /microservices-demo/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, 4 | and in the interest of fostering an open and welcoming community, 5 | we pledge to respect all people who contribute through reporting issues, 6 | posting feature requests, updating documentation, 7 | submitting pull requests or patches, and other activities. 8 | 9 | We are committed to making participation in this project 10 | a harassment-free experience for everyone, 11 | regardless of level of experience, gender, gender identity and expression, 12 | sexual orientation, disability, personal appearance, 13 | body size, race, ethnicity, age, religion, or nationality. 14 | 15 | Examples of unacceptable behavior by participants include: 16 | 17 | * The use of sexualized language or imagery 18 | * Personal attacks 19 | * Trolling or insulting/derogatory comments 20 | * Public or private harassment 21 | * Publishing other's private information, 22 | such as physical or electronic 23 | addresses, without explicit permission 24 | * Other unethical or unprofessional conduct. 25 | 26 | Project maintainers have the right and responsibility to remove, edit, or reject 27 | comments, commits, code, wiki edits, issues, and other contributions 28 | that are not aligned to this Code of Conduct. 29 | By adopting this Code of Conduct, 30 | project maintainers commit themselves to fairly and consistently 31 | applying these principles to every aspect of managing this project. 32 | Project maintainers who do not follow or enforce the Code of Conduct 33 | may be permanently removed from the project team. 34 | 35 | This code of conduct applies both within project spaces and in public spaces 36 | when an individual is representing the project or its community. 37 | 38 | Instances of abusive, harassing, or otherwise unacceptable behavior 39 | may be reported by opening an issue 40 | or contacting one or more of the project maintainers. 41 | 42 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, 43 | available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) 44 | -------------------------------------------------------------------------------- /microservices-demo/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Development Principles (for Googlers) 7 | 8 | There are a few principles for developing or refactoring the service 9 | implementations. Read the [Development Principles 10 | Guide](./docs/development-principles.md). 11 | 12 | ## Contributor License Agreement 13 | 14 | Contributions to this project must be accompanied by a Contributor License 15 | Agreement. You (or your employer) retain the copyright to your contribution; 16 | this simply gives us permission to use and redistribute your contributions as 17 | part of the project. Head over to to see 18 | your current agreements on file or to sign a new one. 19 | 20 | You generally only need to submit a CLA once, so if you've already submitted one 21 | (even if it was for a different project), you probably don't need to do it 22 | again. 23 | 24 | ## Code reviews 25 | 26 | All submissions, including submissions by project members, require review. We 27 | use GitHub pull requests for this purpose. Consult 28 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 29 | information on using pull requests. 30 | 31 | ## Community Guidelines 32 | 33 | This project follows [Google's Open Source Community 34 | Guidelines](https://opensource.google.com/conduct/). 35 | -------------------------------------------------------------------------------- /microservices-demo/README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | **Note:** 4 | 5 | **This demo application serves as a companion for the [Kubernetes Adoption Journey](https://digitalocean.github.io/k8s-adoption-journey/) project. Please follow the Kubernetes adoption journey project for more information and comprehensive guidelines.** 6 | 7 | This application is a clone of this [GoogleCloudPlatform](https://github.com/GoogleCloudPlatform/microservices-demo) project. It will be used as a demo for the K8s adoption journey. This clone of the project has been stripped down to focus only on the major parts as required by the adoption journey. 8 | 9 | ## Prerequisites 10 | 11 | 1. [Tilt](https://tilt.dev/) installed on your local machine. 12 | 2. [Docker Desktop](https://www.docker.com/products/docker-desktop/) installed on your local machine, with built-in Kubernetes cluster enabled and running. 13 | 14 | ## Quick Start 15 | 16 | 1. Run the following command in the project root directory to deploy the **microservices-demo** app to your local Kubernetes cluster: 17 | 18 | ```shell 19 | cp tilt-resources/local/tilt_config.json . 20 | tilt up 21 | ``` 22 | 23 | 2. Open Tilt [web interface](http://localhost:10350/), and wait for all services to be ready. 24 | 3. Access the [web frontend](http://localhost:9090/) in a browser. 25 | 26 | ## Cleaning Up 27 | 28 | Run following command from this project root directory to clean up all resources: 29 | 30 | ```shell 31 | tilt down 32 | ``` 33 | -------------------------------------------------------------------------------- /microservices-demo/Tiltfile: -------------------------------------------------------------------------------- 1 | ######################################################################### 2 | # 3 | # Tiltfile logic 4 | # 5 | ######################################################################### 6 | 7 | 8 | # Import required functions from Tilt extensions 9 | 10 | load( 11 | "ext://namespace", 12 | "namespace_create", 13 | "namespace_inject" 14 | ) 15 | 16 | # Import settings from tilt_config.json 17 | if not os.path.exists("./tilt_config.json"): 18 | fail( 19 | """ 20 | # ================================================ # 21 | # Tilt config file not found in current directory! # 22 | # Please copy a template from tilt-resources dir. # 23 | # # 24 | # E.g.: # 25 | # cp tilt-resources/local/tilt_config.json . # 26 | # ================================================ # 27 | """ 28 | ) 29 | 30 | config.define_string_list("allowed_contexts") 31 | config.define_string("default_registry") 32 | config.define_string("environment") 33 | config.define_string_list("microservices") 34 | config.define_string("namespace") 35 | config.define_string_list("port_forwards") 36 | cfg = config.parse() 37 | 38 | # Compatibilty setting for ARM arch 39 | os.putenv("DOCKER_DEFAULT_PLATFORM", "linux/amd64") 40 | 41 | # Allow default K8S context as stated in the tilt_config.json file 42 | allow_k8s_contexts(cfg.get("allowed_contexts")) 43 | 44 | # Set default registry as stated in the tilt_config.json file 45 | if cfg.get("default_registry") != "": 46 | default_registry(cfg.get("default_registry")) 47 | 48 | # Build each microservice image as stated in the tilt_config.json file 49 | for microservice in cfg.get("microservices"): 50 | if "redis" in microservice: 51 | continue 52 | docker_build( 53 | microservice, 54 | # cartservice is an exception regarding source folder path 55 | "src/{}/src".format(microservice) if "cartservice" in microservice else "src/{}".format(microservice) 56 | ) 57 | 58 | # Create namespace as stated in the tilt_config.json file 59 | namespace_create(cfg.get("namespace")) 60 | 61 | # Deploy each microservice as stated in the tilt_config.json file 62 | for microservice in cfg.get("microservices"): 63 | k8s_yaml( 64 | namespace_inject( 65 | read_file("kustomize/base/{}.yaml".format(microservice)), 66 | cfg.get("namespace") 67 | ) 68 | ) 69 | 70 | # Port forwards as stated in the tilt_config.json file 71 | for port_forward in cfg.get("port_forwards"): 72 | mapping = port_forward.split(":") 73 | if (len(mapping) != 2): 74 | fail( 75 | """ 76 | # =================================================== # 77 | # Invalid port forward specified in tilt_config.json! # 78 | # Should be :. # 79 | # # 80 | # E.g.: frontend:9090 # 81 | # =================================================== # 82 | """ 83 | ) 84 | service = mapping[0] 85 | port = mapping[1] 86 | k8s_resource(service, port_forwards=port) 87 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/base/cartservice.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: cartservice 20 | spec: 21 | replicas: 1 22 | selector: 23 | matchLabels: 24 | app: cartservice 25 | template: 26 | metadata: 27 | labels: 28 | app: cartservice 29 | spec: 30 | serviceAccountName: default 31 | terminationGracePeriodSeconds: 5 32 | securityContext: 33 | fsGroup: 1000 34 | runAsGroup: 1000 35 | runAsNonRoot: true 36 | runAsUser: 1000 37 | containers: 38 | - name: server 39 | securityContext: 40 | allowPrivilegeEscalation: false 41 | capabilities: 42 | drop: 43 | - all 44 | privileged: false 45 | readOnlyRootFilesystem: true 46 | imagePullPolicy: Always 47 | image: cartservice:latest 48 | ports: 49 | - containerPort: 7070 50 | env: 51 | - name: REDIS_ADDR 52 | value: "redis-cart:6379" 53 | resources: 54 | requests: 55 | cpu: 200m 56 | memory: 128Mi 57 | limits: 58 | cpu: 300m 59 | memory: 256Mi 60 | readinessProbe: 61 | timeoutSeconds: 15 62 | initialDelaySeconds: 20 63 | exec: 64 | command: 65 | [ 66 | "/bin/grpc_health_probe", 67 | "-addr=:7070", 68 | "-rpc-timeout=10s", 69 | "-connect-timeout=10s", 70 | ] 71 | livenessProbe: 72 | timeoutSeconds: 15 73 | initialDelaySeconds: 20 74 | periodSeconds: 15 75 | exec: 76 | command: 77 | [ 78 | "/bin/grpc_health_probe", 79 | "-addr=:7070", 80 | "-rpc-timeout=10s", 81 | "-connect-timeout=10s", 82 | ] 83 | 84 | --- 85 | apiVersion: v1 86 | kind: Service 87 | metadata: 88 | name: cartservice 89 | spec: 90 | type: ClusterIP 91 | selector: 92 | app: cartservice 93 | ports: 94 | - name: grpc 95 | port: 7070 96 | targetPort: 7070 97 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/base/currencyservice.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: currencyservice 20 | spec: 21 | replicas: 1 22 | selector: 23 | matchLabels: 24 | app: currencyservice 25 | template: 26 | metadata: 27 | labels: 28 | app: currencyservice 29 | spec: 30 | serviceAccountName: default 31 | terminationGracePeriodSeconds: 5 32 | securityContext: 33 | fsGroup: 1000 34 | runAsGroup: 1000 35 | runAsNonRoot: true 36 | runAsUser: 1000 37 | containers: 38 | - name: server 39 | securityContext: 40 | allowPrivilegeEscalation: false 41 | capabilities: 42 | drop: 43 | - all 44 | privileged: false 45 | readOnlyRootFilesystem: true 46 | imagePullPolicy: Always 47 | image: currencyservice:latest 48 | ports: 49 | - name: grpc 50 | containerPort: 7000 51 | env: 52 | - name: PORT 53 | value: "7000" 54 | - name: DISABLE_TRACING 55 | value: "1" 56 | - name: DISABLE_PROFILER 57 | value: "1" 58 | - name: DISABLE_DEBUGGER 59 | value: "1" 60 | readinessProbe: 61 | timeoutSeconds: 15 62 | initialDelaySeconds: 15 63 | exec: 64 | command: ["/bin/grpc_health_probe", "-rpc-timeout=5s", "-addr=:7000"] 65 | livenessProbe: 66 | timeoutSeconds: 15 67 | initialDelaySeconds: 15 68 | exec: 69 | command: ["/bin/grpc_health_probe", "-rpc-timeout=5s", "-addr=:7000"] 70 | resources: 71 | requests: 72 | cpu: 100m 73 | memory: 128Mi 74 | limits: 75 | cpu: 200m 76 | memory: 256Mi 77 | 78 | --- 79 | apiVersion: v1 80 | kind: Service 81 | metadata: 82 | name: currencyservice 83 | spec: 84 | type: ClusterIP 85 | selector: 86 | app: currencyservice 87 | ports: 88 | - name: grpc 89 | port: 7000 90 | targetPort: 7000 91 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/base/emailservice.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: emailservice 20 | spec: 21 | replicas: 1 22 | selector: 23 | matchLabels: 24 | app: emailservice 25 | template: 26 | metadata: 27 | labels: 28 | app: emailservice 29 | spec: 30 | serviceAccountName: default 31 | terminationGracePeriodSeconds: 5 32 | securityContext: 33 | fsGroup: 1000 34 | runAsGroup: 1000 35 | runAsNonRoot: true 36 | runAsUser: 1000 37 | containers: 38 | - name: server 39 | securityContext: 40 | allowPrivilegeEscalation: false 41 | capabilities: 42 | drop: 43 | - all 44 | privileged: false 45 | readOnlyRootFilesystem: true 46 | imagePullPolicy: Always 47 | image: emailservice:latest 48 | ports: 49 | - containerPort: 8080 50 | env: 51 | - name: PORT 52 | value: "8080" 53 | - name: DISABLE_TRACING 54 | value: "1" 55 | - name: DISABLE_PROFILER 56 | value: "1" 57 | readinessProbe: 58 | timeoutSeconds: 15 59 | periodSeconds: 15 60 | initialDelaySeconds: 15 61 | exec: 62 | command: ["/bin/grpc_health_probe", "-rpc-timeout=5s", "-addr=:8080"] 63 | livenessProbe: 64 | timeoutSeconds: 15 65 | periodSeconds: 15 66 | initialDelaySeconds: 15 67 | exec: 68 | command: ["/bin/grpc_health_probe", "-rpc-timeout=5s", "-addr=:8080"] 69 | resources: 70 | requests: 71 | cpu: 100m 72 | memory: 128Mi 73 | limits: 74 | cpu: 200m 75 | memory: 256Mi 76 | 77 | --- 78 | apiVersion: v1 79 | kind: Service 80 | metadata: 81 | name: emailservice 82 | spec: 83 | type: ClusterIP 84 | selector: 85 | app: emailservice 86 | ports: 87 | - name: grpc 88 | port: 5000 89 | targetPort: 8080 90 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - namespace.yaml 6 | - cartservice.yaml 7 | - checkoutservice.yaml 8 | - currencyservice.yaml 9 | - emailservice.yaml 10 | - frontend.yaml 11 | - paymentservice.yaml 12 | - productcatalogservice.yaml 13 | - recommendationservice.yaml 14 | - redis.yaml 15 | - shippingservice.yaml 16 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/base/namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: microservices-demo 5 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/base/paymentservice.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: paymentservice 20 | spec: 21 | replicas: 1 22 | selector: 23 | matchLabels: 24 | app: paymentservice 25 | template: 26 | metadata: 27 | labels: 28 | app: paymentservice 29 | spec: 30 | serviceAccountName: default 31 | terminationGracePeriodSeconds: 5 32 | securityContext: 33 | fsGroup: 1000 34 | runAsGroup: 1000 35 | runAsNonRoot: true 36 | runAsUser: 1000 37 | containers: 38 | - name: server 39 | securityContext: 40 | allowPrivilegeEscalation: false 41 | capabilities: 42 | drop: 43 | - all 44 | privileged: false 45 | readOnlyRootFilesystem: true 46 | imagePullPolicy: Always 47 | image: paymentservice:latest 48 | ports: 49 | - containerPort: 50051 50 | env: 51 | - name: PORT 52 | value: "50051" 53 | - name: DISABLE_TRACING 54 | value: "1" 55 | - name: DISABLE_PROFILER 56 | value: "1" 57 | - name: DISABLE_DEBUGGER 58 | value: "1" 59 | readinessProbe: 60 | timeoutSeconds: 15 61 | initialDelaySeconds: 15 62 | exec: 63 | command: ["/bin/grpc_health_probe", "-rpc-timeout=5s", "-addr=:50051"] 64 | livenessProbe: 65 | timeoutSeconds: 15 66 | initialDelaySeconds: 15 67 | exec: 68 | command: ["/bin/grpc_health_probe", "-rpc-timeout=5s", "-addr=:50051"] 69 | resources: 70 | requests: 71 | cpu: 100m 72 | memory: 128Mi 73 | limits: 74 | cpu: 200m 75 | memory: 256Mi 76 | 77 | --- 78 | apiVersion: v1 79 | kind: Service 80 | metadata: 81 | name: paymentservice 82 | spec: 83 | type: ClusterIP 84 | selector: 85 | app: paymentservice 86 | ports: 87 | - name: grpc 88 | port: 50051 89 | targetPort: 50051 90 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/base/productcatalogservice.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: productcatalogservice 20 | spec: 21 | replicas: 1 22 | selector: 23 | matchLabels: 24 | app: productcatalogservice 25 | template: 26 | metadata: 27 | labels: 28 | app: productcatalogservice 29 | spec: 30 | serviceAccountName: default 31 | terminationGracePeriodSeconds: 5 32 | securityContext: 33 | fsGroup: 1000 34 | runAsGroup: 1000 35 | runAsNonRoot: true 36 | runAsUser: 1000 37 | containers: 38 | - name: server 39 | securityContext: 40 | allowPrivilegeEscalation: false 41 | capabilities: 42 | drop: 43 | - all 44 | privileged: false 45 | readOnlyRootFilesystem: true 46 | imagePullPolicy: Always 47 | image: productcatalogservice:latest 48 | ports: 49 | - containerPort: 3550 50 | env: 51 | - name: PORT 52 | value: "3550" 53 | - name: DISABLE_STATS 54 | value: "1" 55 | - name: DISABLE_TRACING 56 | value: "1" 57 | - name: DISABLE_PROFILER 58 | value: "1" 59 | # - name: JAEGER_SERVICE_ADDR 60 | # value: "jaeger-collector:14268" 61 | readinessProbe: 62 | timeoutSeconds: 15 63 | initialDelaySeconds: 15 64 | exec: 65 | command: ["/bin/grpc_health_probe", "-addr=:3550"] 66 | livenessProbe: 67 | timeoutSeconds: 15 68 | initialDelaySeconds: 15 69 | exec: 70 | command: ["/bin/grpc_health_probe", "-addr=:3550"] 71 | resources: 72 | requests: 73 | cpu: 100m 74 | memory: 64Mi 75 | limits: 76 | cpu: 200m 77 | memory: 128Mi 78 | 79 | --- 80 | apiVersion: v1 81 | kind: Service 82 | metadata: 83 | name: productcatalogservice 84 | spec: 85 | type: ClusterIP 86 | selector: 87 | app: productcatalogservice 88 | ports: 89 | - name: grpc 90 | port: 3550 91 | targetPort: 3550 92 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/base/recommendationservice.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: recommendationservice 20 | spec: 21 | replicas: 1 22 | selector: 23 | matchLabels: 24 | app: recommendationservice 25 | template: 26 | metadata: 27 | labels: 28 | app: recommendationservice 29 | spec: 30 | serviceAccountName: default 31 | terminationGracePeriodSeconds: 5 32 | securityContext: 33 | fsGroup: 1000 34 | runAsGroup: 1000 35 | runAsNonRoot: true 36 | runAsUser: 1000 37 | containers: 38 | - name: server 39 | securityContext: 40 | allowPrivilegeEscalation: false 41 | capabilities: 42 | drop: 43 | - all 44 | privileged: false 45 | readOnlyRootFilesystem: true 46 | imagePullPolicy: Always 47 | image: recommendationservice:latest 48 | ports: 49 | - containerPort: 8080 50 | readinessProbe: 51 | timeoutSeconds: 15 52 | initialDelaySeconds: 15 53 | periodSeconds: 15 54 | exec: 55 | command: ["/bin/grpc_health_probe", "-addr=:8080"] 56 | livenessProbe: 57 | timeoutSeconds: 15 58 | initialDelaySeconds: 15 59 | periodSeconds: 15 60 | exec: 61 | command: ["/bin/grpc_health_probe", "-addr=:8080"] 62 | env: 63 | - name: PORT 64 | value: "8080" 65 | - name: PRODUCT_CATALOG_SERVICE_ADDR 66 | value: "productcatalogservice:3550" 67 | - name: DISABLE_TRACING 68 | value: "1" 69 | - name: DISABLE_PROFILER 70 | value: "1" 71 | - name: DISABLE_DEBUGGER 72 | value: "1" 73 | resources: 74 | requests: 75 | cpu: 100m 76 | memory: 220Mi 77 | limits: 78 | cpu: 200m 79 | memory: 450Mi 80 | 81 | --- 82 | apiVersion: v1 83 | kind: Service 84 | metadata: 85 | name: recommendationservice 86 | spec: 87 | type: ClusterIP 88 | selector: 89 | app: recommendationservice 90 | ports: 91 | - name: grpc 92 | port: 8080 93 | targetPort: 8080 94 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/base/redis.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: redis-cart 20 | spec: 21 | replicas: 1 22 | selector: 23 | matchLabels: 24 | app: redis-cart 25 | template: 26 | metadata: 27 | labels: 28 | app: redis-cart 29 | spec: 30 | securityContext: 31 | fsGroup: 1000 32 | runAsGroup: 1000 33 | runAsNonRoot: true 34 | runAsUser: 1000 35 | containers: 36 | - name: redis 37 | securityContext: 38 | allowPrivilegeEscalation: false 39 | capabilities: 40 | drop: 41 | - all 42 | privileged: false 43 | readOnlyRootFilesystem: true 44 | image: redis:alpine 45 | ports: 46 | - containerPort: 6379 47 | readinessProbe: 48 | periodSeconds: 5 49 | tcpSocket: 50 | port: 6379 51 | livenessProbe: 52 | periodSeconds: 5 53 | tcpSocket: 54 | port: 6379 55 | volumeMounts: 56 | - mountPath: /data 57 | name: redis-data 58 | resources: 59 | limits: 60 | memory: 256Mi 61 | cpu: 125m 62 | requests: 63 | cpu: 70m 64 | memory: 200Mi 65 | volumes: 66 | - name: redis-data 67 | emptyDir: {} 68 | 69 | --- 70 | apiVersion: v1 71 | kind: Service 72 | metadata: 73 | name: redis-cart 74 | spec: 75 | type: ClusterIP 76 | selector: 77 | app: redis-cart 78 | ports: 79 | - name: tls-redis 80 | port: 6379 81 | targetPort: 6379 82 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/base/shippingservice.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: shippingservice 20 | spec: 21 | replicas: 1 22 | selector: 23 | matchLabels: 24 | app: shippingservice 25 | template: 26 | metadata: 27 | labels: 28 | app: shippingservice 29 | spec: 30 | serviceAccountName: default 31 | securityContext: 32 | fsGroup: 1000 33 | runAsGroup: 1000 34 | runAsNonRoot: true 35 | runAsUser: 1000 36 | containers: 37 | - name: server 38 | securityContext: 39 | allowPrivilegeEscalation: false 40 | capabilities: 41 | drop: 42 | - all 43 | privileged: false 44 | readOnlyRootFilesystem: true 45 | imagePullPolicy: Always 46 | image: shippingservice:latest 47 | ports: 48 | - containerPort: 50051 49 | env: 50 | - name: PORT 51 | value: "50051" 52 | - name: DISABLE_STATS 53 | value: "1" 54 | - name: DISABLE_TRACING 55 | value: "1" 56 | - name: DISABLE_PROFILER 57 | value: "1" 58 | # - name: JAEGER_SERVICE_ADDR 59 | # value: "jaeger-collector:14268" 60 | readinessProbe: 61 | timeoutSeconds: 15 62 | periodSeconds: 15 63 | initialDelaySeconds: 15 64 | exec: 65 | command: ["/bin/grpc_health_probe", "-addr=:50051"] 66 | livenessProbe: 67 | timeoutSeconds: 15 68 | initialDelaySeconds: 15 69 | exec: 70 | command: ["/bin/grpc_health_probe", "-addr=:50051"] 71 | resources: 72 | requests: 73 | cpu: 100m 74 | memory: 64Mi 75 | limits: 76 | cpu: 200m 77 | memory: 128Mi 78 | 79 | --- 80 | apiVersion: v1 81 | kind: Service 82 | metadata: 83 | name: shippingservice 84 | spec: 85 | type: ClusterIP 86 | selector: 87 | app: shippingservice 88 | ports: 89 | - name: grpc 90 | port: 50051 91 | targetPort: 50051 92 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: microservices-demo-dev 5 | commonLabels: 6 | variant: dev 7 | 8 | resources: 9 | - ../base 10 | 11 | images: 12 | - name: cartservice 13 | newName: registry.digitalocean.com/microservices-demo/cartservice 14 | newTag: v1.0.0 15 | - name: checkoutservice 16 | newName: registry.digitalocean.com/microservices-demo/checkoutservice 17 | newTag: v1.0.0 18 | - name: currencyservice 19 | newName: registry.digitalocean.com/microservices-demo/currencyservice 20 | newTag: v1.0.0 21 | - name: emailservice 22 | newName: registry.digitalocean.com/microservices-demo/emailservice 23 | newTag: v1.0.0 24 | - name: frontend 25 | newName: registry.digitalocean.com/microservices-demo/frontend 26 | newTag: v1.0.0 27 | - name: paymentservice 28 | newName: registry.digitalocean.com/microservices-demo/paymentservice 29 | newTag: v1.0.0 30 | - name: productcatalogservice 31 | newName: registry.digitalocean.com/microservices-demo/productcatalogservice 32 | newTag: v1.0.0 33 | - name: recommendationservice 34 | newName: registry.digitalocean.com/microservices-demo/recommendationservice 35 | newTag: v1.0.0 36 | - name: shippingservice 37 | newName: registry.digitalocean.com/microservices-demo/shippingservice 38 | newTag: v1.0.0 39 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - dev 6 | - staging 7 | - prod 8 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/prod/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: microservices-demo-prod 5 | commonLabels: 6 | variant: prod 7 | 8 | resources: 9 | - ../base 10 | 11 | images: 12 | - name: cartservice 13 | newName: registry.digitalocean.com/microservices-demo/cartservice 14 | newTag: v1.0.0 15 | - name: checkoutservice 16 | newName: registry.digitalocean.com/microservices-demo/checkoutservice 17 | newTag: v1.0.0 18 | - name: currencyservice 19 | newName: registry.digitalocean.com/microservices-demo/currencyservice 20 | newTag: v1.0.0 21 | - name: emailservice 22 | newName: registry.digitalocean.com/microservices-demo/emailservice 23 | newTag: v1.0.0 24 | - name: frontend 25 | newName: registry.digitalocean.com/microservices-demo/frontend 26 | newTag: v1.0.0 27 | - name: paymentservice 28 | newName: registry.digitalocean.com/microservices-demo/paymentservice 29 | newTag: v1.0.0 30 | - name: productcatalogservice 31 | newName: registry.digitalocean.com/microservices-demo/productcatalogservice 32 | newTag: v1.0.0 33 | - name: recommendationservice 34 | newName: registry.digitalocean.com/microservices-demo/recommendationservice 35 | newTag: v1.0.0 36 | - name: shippingservice 37 | newName: registry.digitalocean.com/microservices-demo/shippingservice 38 | newTag: v1.0.0 39 | 40 | replicas: 41 | - name: cartservice 42 | count: 2 43 | - name: checkoutservice 44 | count: 2 45 | - name: currencyservice 46 | count: 2 47 | - name: emailservice 48 | count: 2 49 | - name: frontend 50 | count: 2 51 | - name: paymentservice 52 | count: 2 53 | - name: productcatalogservice 54 | count: 2 55 | - name: recommendationservice 56 | count: 2 57 | - name: shippingservice 58 | count: 2 59 | -------------------------------------------------------------------------------- /microservices-demo/kustomize/staging/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: microservices-demo-staging 5 | commonLabels: 6 | variant: staging 7 | 8 | resources: 9 | - ../base 10 | 11 | images: 12 | - name: cartservice 13 | newName: registry.digitalocean.com/microservices-demo/cartservice 14 | newTag: v1.0.0 15 | - name: checkoutservice 16 | newName: registry.digitalocean.com/microservices-demo/checkoutservice 17 | newTag: v1.0.0 18 | - name: currencyservice 19 | newName: registry.digitalocean.com/microservices-demo/currencyservice 20 | newTag: v1.0.0 21 | - name: emailservice 22 | newName: registry.digitalocean.com/microservices-demo/emailservice 23 | newTag: v1.0.0 24 | - name: frontend 25 | newName: registry.digitalocean.com/microservices-demo/frontend 26 | newTag: v1.0.0 27 | - name: paymentservice 28 | newName: registry.digitalocean.com/microservices-demo/paymentservice 29 | newTag: v1.0.0 30 | - name: productcatalogservice 31 | newName: registry.digitalocean.com/microservices-demo/productcatalogservice 32 | newTag: v1.0.0 33 | - name: recommendationservice 34 | newName: registry.digitalocean.com/microservices-demo/recommendationservice 35 | newTag: v1.0.0 36 | - name: shippingservice 37 | newName: registry.digitalocean.com/microservices-demo/shippingservice 38 | newTag: v1.0.0 39 | 40 | replicas: 41 | - name: cartservice 42 | count: 2 43 | - name: checkoutservice 44 | count: 2 45 | - name: currencyservice 46 | count: 2 47 | - name: emailservice 48 | count: 2 49 | - name: frontend 50 | count: 2 51 | - name: paymentservice 52 | count: 2 53 | - name: productcatalogservice 54 | count: 2 55 | - name: recommendationservice 56 | count: 2 57 | - name: shippingservice 58 | count: 2 59 | -------------------------------------------------------------------------------- /microservices-demo/release-scripts/README.md: -------------------------------------------------------------------------------- 1 | # Overview of the Release Scripts 2 | 3 | This directory contains the scripts for creating a new `microservices-demo` release. 4 | 5 | ## Create a New Release 6 | 7 | ### 1. Decide on the next release version number using [semantic versioning](https://semver.org/). 8 | 9 | - Look at the [commits since the previous release](https://github.com/GoogleCloudPlatform/microservices-demo/commits/main). 10 | 11 | #### 2. Open a new terminal 12 | 13 | #### 3. Make sure you have `gsed` installed. If not, `brew install gnu-sed`. 14 | 15 | #### 4. Set the following environment variables 16 | 17 | - `TAG` - This is the new version (e.g., `v0.3.5`). 18 | - `REPO_PREFIX` - This is the Docker repository. 19 | 20 | ##### Example 21 | 22 | ```shell 23 | export TAG=v0.3.5 24 | export REPO_PREFIX=gcr.io/google-samples/microservices-demo 25 | ``` 26 | 27 | #### 5. Run `./release-scripts/make-release.sh` 28 | 29 | - Make sure you run `./hack/make-release.sh` from this project's root folder — **not** from inside the `release-scripts/` folder. 30 | - This script: 31 | 1. uses `make-docker-images.sh` to build and push a Docker image for each microservice to the previously specified repository. 32 | 1. uses `make-release-artifacts.sh` to regenerates (and update the image $TAGS) YAML file at `./release/kubernetes-manifests.yaml`. 33 | 1. runs `git tag` and pushes a new branch (e.g., `release/v0.3.5`) with the changes to `release/kubernetes-manifests.yaml`. 34 | 35 | #### 6. [Draft a new release on GitHub](https://github.com/GoogleCloudPlatform/microservices-demo/releases). 36 | 37 | - Summarize the [commits since the previous release](https://github.com/GoogleCloudPlatform/microservices-demo/commits/main). 38 | - See previous releases for inspiration on release notes. 39 | 40 | #### 7. Create a new pull-request 41 | 42 | - When you ran `make-release.sh`, it created a new branch (e.g., `release/v0.3.5`). 43 | - Include the new release draft in the pull-request description for reviewers to see. 44 | 45 | #### 8. Once your pull-request is approved, merge it 46 | 47 | #### 9. Deploy `release/kubernetes-manifests.yaml` 48 | 49 | ```shell 50 | kubectl apply -f ./release/kubernetes-manifests.yaml 51 | ``` 52 | -------------------------------------------------------------------------------- /microservices-demo/release-scripts/license_header.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /microservices-demo/release-scripts/make-cnb-docker-images.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 5 | 6 | log() { echo "$1" >&2; } 7 | 8 | TAG="${TAG:?TAG env variable must be specified}" 9 | REPO_PREFIX="${REPO_PREFIX:?REPO_PREFIX env variable must be specified}" 10 | 11 | while IFS= read -d $'\0' -r dir; do 12 | # build image 13 | svcname="$(basename "${dir}")" 14 | builddir="${dir}" 15 | #PR 516 moved cartservice build artifacts one level down to src 16 | if [ $svcname == "cartservice" ] 17 | then 18 | builddir="${dir}/src" 19 | fi 20 | ## skipping loadgenerator service building as it's used only in CI for tests 21 | if [ $svcname == "loadgenerator" ] 22 | then 23 | continue 24 | fi 25 | image="${REPO_PREFIX}/$svcname:$TAG" 26 | ( 27 | cd "${builddir}" 28 | log "Building and pushing: ${image}" 29 | ## we are not using the --publish pack flag due to an issue preventing the pack CLI from pushing to DOCR 30 | pack build ${image} --builder gcr.io/buildpacks/builder:v1 31 | docker push ${image} 32 | ) 33 | done < <(find "${SCRIPTDIR}/../src" -mindepth 1 -maxdepth 1 -type d -print0) 34 | 35 | log "Successfully built and pushed all images." 36 | -------------------------------------------------------------------------------- /microservices-demo/release-scripts/make-docker-images.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2019 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Builds and pushes docker image for each demo microservice. 18 | 19 | set -euo pipefail 20 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 21 | 22 | log() { echo "$1" >&2; } 23 | 24 | TAG="${TAG:?TAG env variable must be specified}" 25 | REPO_PREFIX="${REPO_PREFIX:?REPO_PREFIX env variable must be specified}" 26 | 27 | while IFS= read -d $'\0' -r dir; do 28 | # build image 29 | svcname="$(basename "${dir}")" 30 | builddir="${dir}" 31 | #PR 516 moved cartservice build artifacts one level down to src 32 | if [ $svcname == "cartservice" ] 33 | then 34 | builddir="${dir}/src" 35 | fi 36 | image="${REPO_PREFIX}/$svcname:$TAG" 37 | ( 38 | cd "${builddir}" 39 | log "Building and pushing: ${image}" 40 | docker buildx build --platform linux/amd64 -t "${image}" --push . 41 | ) 42 | done < <(find "${SCRIPTDIR}/../src" -mindepth 1 -maxdepth 1 -type d -print0) 43 | 44 | log "Successfully built and pushed all images." 45 | -------------------------------------------------------------------------------- /microservices-demo/release-scripts/make-release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2019 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # This script creates a new release by: 18 | # - 1. building/pushing images 19 | # - 2. injecting tags into YAML manifests 20 | # - 3. creating a new git tag 21 | # - 4. pushing the tag/commit to main. 22 | 23 | set -euo pipefail 24 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 25 | [[ -n "${DEBUG:-}" ]] && set -x 26 | 27 | log() { echo "$1" >&2; } 28 | fail() { log "$1"; exit 1; } 29 | 30 | TAG="${TAG:?TAG env variable must be specified}" 31 | REPO_PREFIX="${REPO_PREFIX:?REPO_PREFIX env variable must be specified e.g. gcr.io\/google-samples\/microservices-demo}" 32 | 33 | if [[ "$TAG" != v* ]]; then 34 | fail "\$TAG must start with 'v', e.g. v0.1.0 (got: $TAG)" 35 | fi 36 | 37 | # build and push images 38 | "${SCRIPTDIR}"/make-docker-images.sh 39 | 40 | # update yaml 41 | "${SCRIPTDIR}"/make-release-artifacts.sh 42 | 43 | # create git release / push to new branch 44 | git checkout -b "release/${TAG}" 45 | git add "${SCRIPTDIR}/../release/" 46 | git commit --allow-empty -m "Release $TAG" 47 | log "Pushing k8s manifests to release/${TAG}..." 48 | git tag "$TAG" 49 | git push --set-upstream origin "release/${TAG}" 50 | git push --tags 51 | 52 | log "Successfully tagged release $TAG." 53 | -------------------------------------------------------------------------------- /microservices-demo/src/.gitignore: -------------------------------------------------------------------------------- 1 | # Go: for the time being we are not checking in the vendor/ directories to git 2 | # to prevent the repo from getting larger forever. In each Go service, you can 3 | # run "dep ensure --vendor-only" to download the dependencies to vendor/ based 4 | # on the Gopkg.{toml,lock} files in that directory. 5 | vendor/ 6 | -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/.gitignore: -------------------------------------------------------------------------------- 1 | **/bin/ 2 | **/obj/ 3 | .vs/*.* 4 | -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/cartservice.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cartservice", "src\cartservice.csproj", "{2348C29F-E8D3-4955-916D-D609CBC97FCB}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cartservice.tests", "tests\cartservice.tests.csproj", "{59825342-CE64-4AFA-8744-781692C0811B}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|x64 = Debug|x64 14 | Debug|x86 = Debug|x86 15 | Release|Any CPU = Release|Any CPU 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {2348C29F-E8D3-4955-916D-D609CBC97FCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {2348C29F-E8D3-4955-916D-D609CBC97FCB}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {2348C29F-E8D3-4955-916D-D609CBC97FCB}.Debug|x64.ActiveCfg = Debug|Any CPU 26 | {2348C29F-E8D3-4955-916D-D609CBC97FCB}.Debug|x64.Build.0 = Debug|Any CPU 27 | {2348C29F-E8D3-4955-916D-D609CBC97FCB}.Debug|x86.ActiveCfg = Debug|Any CPU 28 | {2348C29F-E8D3-4955-916D-D609CBC97FCB}.Debug|x86.Build.0 = Debug|Any CPU 29 | {2348C29F-E8D3-4955-916D-D609CBC97FCB}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {2348C29F-E8D3-4955-916D-D609CBC97FCB}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {2348C29F-E8D3-4955-916D-D609CBC97FCB}.Release|x64.ActiveCfg = Release|Any CPU 32 | {2348C29F-E8D3-4955-916D-D609CBC97FCB}.Release|x64.Build.0 = Release|Any CPU 33 | {2348C29F-E8D3-4955-916D-D609CBC97FCB}.Release|x86.ActiveCfg = Release|Any CPU 34 | {2348C29F-E8D3-4955-916D-D609CBC97FCB}.Release|x86.Build.0 = Release|Any CPU 35 | {59825342-CE64-4AFA-8744-781692C0811B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {59825342-CE64-4AFA-8744-781692C0811B}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {59825342-CE64-4AFA-8744-781692C0811B}.Debug|x64.ActiveCfg = Debug|Any CPU 38 | {59825342-CE64-4AFA-8744-781692C0811B}.Debug|x64.Build.0 = Debug|Any CPU 39 | {59825342-CE64-4AFA-8744-781692C0811B}.Debug|x86.ActiveCfg = Debug|Any CPU 40 | {59825342-CE64-4AFA-8744-781692C0811B}.Debug|x86.Build.0 = Debug|Any CPU 41 | {59825342-CE64-4AFA-8744-781692C0811B}.Release|Any CPU.ActiveCfg = Release|Any CPU 42 | {59825342-CE64-4AFA-8744-781692C0811B}.Release|Any CPU.Build.0 = Release|Any CPU 43 | {59825342-CE64-4AFA-8744-781692C0811B}.Release|x64.ActiveCfg = Release|Any CPU 44 | {59825342-CE64-4AFA-8744-781692C0811B}.Release|x64.Build.0 = Release|Any CPU 45 | {59825342-CE64-4AFA-8744-781692C0811B}.Release|x86.ActiveCfg = Release|Any CPU 46 | {59825342-CE64-4AFA-8744-781692C0811B}.Release|x86.Build.0 = Release|Any CPU 47 | EndGlobalSection 48 | EndGlobal 49 | -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/src/.dockerignore: -------------------------------------------------------------------------------- 1 | **/*.sh 2 | **/*.bat 3 | **/bin/ 4 | **/obj/ 5 | **/out/ 6 | Dockerfile* -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/src/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # https://mcr.microsoft.com/v2/dotnet/sdk/tags/list 16 | FROM mcr.microsoft.com/dotnet/sdk:6.0.400 as builder 17 | WORKDIR /app 18 | COPY cartservice.csproj . 19 | RUN dotnet restore cartservice.csproj -r linux-musl-x64 20 | COPY . . 21 | RUN dotnet publish cartservice.csproj -p:PublishSingleFile=true -r linux-musl-x64 --self-contained true -p:PublishTrimmed=True -p:TrimMode=Link -c release -o /cartservice --no-restore 22 | 23 | # https://mcr.microsoft.com/v2/dotnet/runtime-deps/tags/list 24 | FROM mcr.microsoft.com/dotnet/runtime-deps:6.0.8-alpine3.16-amd64 25 | RUN GRPC_HEALTH_PROBE_VERSION=v0.4.11 && \ 26 | wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ 27 | chmod +x /bin/grpc_health_probe 28 | WORKDIR /app 29 | COPY --from=builder /cartservice . 30 | ENV ASPNETCORE_URLS http://*:7070 31 | ENV DOTNET_EnableDiagnostics=0 32 | ENTRYPOINT ["/app/cartservice"] 33 | -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/src/Dockerfile.debug: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build 16 | WORKDIR /app 17 | COPY . . 18 | RUN dotnet restore cartservice.csproj 19 | RUN dotnet build "./cartservice.csproj" -c Debug -o /out 20 | 21 | FROM build AS publish 22 | RUN dotnet publish cartservice.csproj -c Debug -o /out 23 | 24 | # Building final image used in running container 25 | FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS final 26 | # Installing procps on the container to enable debugging of .NET Core 27 | RUN apt-get update \ 28 | && apt-get install -y unzip procps wget 29 | RUN GRPC_HEALTH_PROBE_VERSION=v0.4.11 && \ 30 | wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ 31 | chmod +x /bin/grpc_health_probe 32 | WORKDIR /app 33 | COPY --from=publish /out . 34 | ENV ASPNETCORE_URLS=http://*:7070 35 | 36 | ENTRYPOINT ["dotnet", "cartservice.dll"] 37 | -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/src/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | using Microsoft.AspNetCore.Hosting; 16 | using Microsoft.Extensions.Hosting; 17 | using cartservice; 18 | 19 | CreateHostBuilder(args).Build().Run(); 20 | 21 | static IHostBuilder CreateHostBuilder(string[] args) => 22 | Host.CreateDefaultBuilder(args) 23 | .ConfigureWebHostDefaults(webBuilder => 24 | { 25 | webBuilder.UseStartup(); 26 | }); -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/src/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Diagnostics.HealthChecks; 4 | using Microsoft.AspNetCore.Hosting; 5 | using Microsoft.AspNetCore.Http; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.DependencyInjection; 8 | using Microsoft.Extensions.Diagnostics.HealthChecks; 9 | using Microsoft.Extensions.Hosting; 10 | using cartservice.cartstore; 11 | using cartservice.services; 12 | using Microsoft.Extensions.Caching.StackExchangeRedis; 13 | 14 | namespace cartservice 15 | { 16 | public class Startup 17 | { 18 | public Startup(IConfiguration configuration) 19 | { 20 | Configuration = configuration; 21 | } 22 | 23 | public IConfiguration Configuration { get; } 24 | 25 | // This method gets called by the runtime. Use this method to add services to the container. 26 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 27 | public void ConfigureServices(IServiceCollection services) 28 | { 29 | string redisAddress = Configuration["REDIS_ADDR"]; 30 | if (!string.IsNullOrEmpty(redisAddress)) 31 | { 32 | services.AddStackExchangeRedisCache(options => 33 | { 34 | options.Configuration = redisAddress; 35 | }); 36 | } 37 | else 38 | { 39 | Console.WriteLine("Redis cache host(hostname+port) was not specified. Starting a cart service using in memory store"); 40 | services.AddDistributedMemoryCache(); 41 | } 42 | 43 | services.AddSingleton(); 44 | 45 | services.AddGrpc(); 46 | } 47 | 48 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 49 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 50 | { 51 | if (env.IsDevelopment()) 52 | { 53 | app.UseDeveloperExceptionPage(); 54 | } 55 | 56 | app.UseRouting(); 57 | 58 | app.UseEndpoints(endpoints => 59 | { 60 | endpoints.MapGrpcService(); 61 | endpoints.MapGrpcService(); 62 | 63 | endpoints.MapGet("/", async context => 64 | { 65 | await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); 66 | }); 67 | }); 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/src/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | "Kestrel": { 11 | "EndpointDefaults": { 12 | "Protocols": "Http2" 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/src/cartservice.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/src/cartstore/ICartStore.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | using System.Threading.Tasks; 16 | 17 | namespace cartservice.cartstore 18 | { 19 | public interface ICartStore 20 | { 21 | Task AddItemAsync(string userId, string productId, int quantity); 22 | Task EmptyCartAsync(string userId); 23 | Task GetCartAsync(string userId); 24 | bool Ping(); 25 | } 26 | } -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/src/protos/Cart.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package hipstershop; 18 | 19 | // -----------------Cart service----------------- 20 | 21 | service CartService { 22 | rpc AddItem(AddItemRequest) returns (Empty) {} 23 | rpc GetCart(GetCartRequest) returns (Cart) {} 24 | rpc EmptyCart(EmptyCartRequest) returns (Empty) {} 25 | } 26 | 27 | message CartItem { 28 | string product_id = 1; 29 | int32 quantity = 2; 30 | } 31 | 32 | message AddItemRequest { 33 | string user_id = 1; 34 | CartItem item = 2; 35 | } 36 | 37 | message EmptyCartRequest { 38 | string user_id = 1; 39 | } 40 | 41 | message GetCartRequest { 42 | string user_id = 1; 43 | } 44 | 45 | message Cart { 46 | string user_id = 1; 47 | repeated CartItem items = 2; 48 | } 49 | 50 | message Empty {} 51 | -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/src/services/CartService.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | using System; 16 | using System.Threading.Tasks; 17 | using Grpc.Core; 18 | using Microsoft.Extensions.Logging; 19 | using cartservice.cartstore; 20 | using Hipstershop; 21 | 22 | namespace cartservice.services 23 | { 24 | public class CartService : Hipstershop.CartService.CartServiceBase 25 | { 26 | private readonly static Empty Empty = new Empty(); 27 | private readonly ICartStore _cartStore; 28 | 29 | public CartService(ICartStore cartStore) 30 | { 31 | _cartStore = cartStore; 32 | } 33 | 34 | public async override Task AddItem(AddItemRequest request, ServerCallContext context) 35 | { 36 | await _cartStore.AddItemAsync(request.UserId, request.Item.ProductId, request.Item.Quantity); 37 | return Empty; 38 | } 39 | 40 | public override Task GetCart(GetCartRequest request, ServerCallContext context) 41 | { 42 | return _cartStore.GetCartAsync(request.UserId); 43 | } 44 | 45 | public async override Task EmptyCart(EmptyCartRequest request, ServerCallContext context) 46 | { 47 | await _cartStore.EmptyCartAsync(request.UserId); 48 | return Empty; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/src/services/HealthCheckService.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | using System; 16 | using System.Threading.Tasks; 17 | using Grpc.Core; 18 | using Grpc.Health.V1; 19 | using static Grpc.Health.V1.Health; 20 | using cartservice.cartstore; 21 | 22 | namespace cartservice.services 23 | { 24 | internal class HealthCheckService : HealthBase 25 | { 26 | private ICartStore _cartStore { get; } 27 | 28 | public HealthCheckService (ICartStore cartStore) 29 | { 30 | _cartStore = cartStore; 31 | } 32 | 33 | public override Task Check(HealthCheckRequest request, ServerCallContext context) 34 | { 35 | Console.WriteLine ("Checking CartService Health"); 36 | return Task.FromResult(new HealthCheckResponse { 37 | Status = _cartStore.Ping() ? HealthCheckResponse.Types.ServingStatus.Serving : HealthCheckResponse.Types.ServingStatus.NotServing 38 | }); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/tests/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/* 2 | /obj/* 3 | /.vs/* -------------------------------------------------------------------------------- /microservices-demo/src/cartservice/tests/cartservice.tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /microservices-demo/src/checkoutservice/.dockerignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | -------------------------------------------------------------------------------- /microservices-demo/src/checkoutservice/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM golang:1.18.4-alpine as builder 16 | RUN apk add --no-cache ca-certificates git 17 | RUN apk add build-base 18 | WORKDIR /src 19 | 20 | # restore dependencies 21 | COPY go.mod go.sum ./ 22 | RUN go mod download 23 | 24 | COPY . . 25 | 26 | # Skaffold passes in debug-oriented compiler flags 27 | ARG SKAFFOLD_GO_GCFLAGS 28 | RUN go build -gcflags="${SKAFFOLD_GO_GCFLAGS}" -o /checkoutservice . 29 | 30 | FROM alpine as release 31 | RUN apk add --no-cache ca-certificates 32 | RUN GRPC_HEALTH_PROBE_VERSION=v0.4.11 && \ 33 | wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ 34 | chmod +x /bin/grpc_health_probe 35 | WORKDIR /src 36 | COPY --from=builder /checkoutservice /src/checkoutservice 37 | 38 | # Definition of this variable is used by 'skaffold debug' to identify a golang binary. 39 | # Default behavior - a failure prints a stack trace for the current goroutine. 40 | # See https://golang.org/pkg/runtime/ 41 | ENV GOTRACEBACK=single 42 | 43 | EXPOSE 5050 44 | ENTRYPOINT ["/src/checkoutservice"] 45 | -------------------------------------------------------------------------------- /microservices-demo/src/checkoutservice/README.md: -------------------------------------------------------------------------------- 1 | # checkoutservice 2 | 3 | Run the following command to restore dependencies to `vendor/` directory: 4 | 5 | dep ensure --vendor-only 6 | -------------------------------------------------------------------------------- /microservices-demo/src/checkoutservice/genproto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # [START gke_checkoutservice_genproto] 18 | 19 | PATH=$PATH:$GOPATH/bin 20 | protodir=../../pb 21 | 22 | protoc --go_out=plugins=grpc:genproto -I $protodir $protodir/demo.proto 23 | 24 | # [END gke_checkoutservice_genproto] -------------------------------------------------------------------------------- /microservices-demo/src/checkoutservice/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/GoogleCloudPlatform/microservices-demo/src/checkoutservice 2 | 3 | go 1.18 4 | 5 | require ( 6 | cloud.google.com/go/profiler v0.3.0 7 | contrib.go.opencensus.io/exporter/jaeger v0.2.1 8 | contrib.go.opencensus.io/exporter/stackdriver v0.13.12 9 | github.com/golang/protobuf v1.5.2 10 | github.com/google/uuid v1.3.0 11 | github.com/sirupsen/logrus v1.8.1 12 | go.opencensus.io v0.23.0 13 | golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b 14 | google.golang.org/grpc v1.48.0 15 | ) 16 | 17 | require ( 18 | cloud.google.com/go v0.100.2 // indirect 19 | cloud.google.com/go/compute v1.6.1 // indirect 20 | cloud.google.com/go/monitoring v1.1.0 // indirect 21 | cloud.google.com/go/trace v1.0.0 // indirect 22 | github.com/aws/aws-sdk-go v1.43.31 // indirect 23 | github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect 24 | github.com/cespare/xxhash v1.1.0 // indirect 25 | github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect 26 | github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 // indirect 27 | github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect 28 | github.com/envoyproxy/protoc-gen-validate v0.1.0 // indirect 29 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 30 | github.com/google/go-cmp v0.5.8 // indirect 31 | github.com/google/pprof v0.0.0-20220412212628-83db2b799d1f // indirect 32 | github.com/googleapis/gax-go/v2 v2.4.0 // indirect 33 | github.com/jmespath/go-jmespath v0.4.0 // indirect 34 | github.com/prometheus/prometheus v2.5.0+incompatible // indirect 35 | github.com/uber/jaeger-client-go v2.25.0+incompatible // indirect 36 | golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect 37 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect 38 | golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect 39 | golang.org/x/text v0.3.7 // indirect 40 | google.golang.org/api v0.78.0 // indirect 41 | google.golang.org/appengine v1.6.7 // indirect 42 | google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335 // indirect 43 | google.golang.org/protobuf v1.28.0 // indirect 44 | ) 45 | -------------------------------------------------------------------------------- /microservices-demo/src/currencyservice/.dockerignore: -------------------------------------------------------------------------------- 1 | client.js 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /microservices-demo/src/currencyservice/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /microservices-demo/src/currencyservice/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM node:18-alpine as base 16 | 17 | FROM base as builder 18 | 19 | # Some packages (e.g. @google-cloud/profiler) require additional 20 | # deps for post-install scripts 21 | RUN apk add --update --no-cache \ 22 | python3 \ 23 | make \ 24 | g++ 25 | 26 | WORKDIR /usr/src/app 27 | 28 | COPY package*.json ./ 29 | 30 | RUN npm install --only=production 31 | 32 | FROM base 33 | 34 | RUN GRPC_HEALTH_PROBE_VERSION=v0.4.11 && \ 35 | wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ 36 | chmod +x /bin/grpc_health_probe 37 | 38 | WORKDIR /usr/src/app 39 | 40 | COPY --from=builder /usr/src/app/node_modules ./node_modules 41 | 42 | COPY . . 43 | 44 | EXPOSE 7000 45 | 46 | ENTRYPOINT [ "node", "server.js" ] 47 | -------------------------------------------------------------------------------- /microservices-demo/src/currencyservice/client.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2015 gRPC authors. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | require('@google-cloud/trace-agent').start(); 19 | 20 | const path = require('path'); 21 | const grpc = require('grpc'); 22 | const leftPad = require('left-pad'); 23 | const pino = require('pino'); 24 | 25 | const PROTO_PATH = path.join(__dirname, './proto/demo.proto'); 26 | const PORT = 7000; 27 | 28 | const shopProto = grpc.load(PROTO_PATH).hipstershop; 29 | const client = new shopProto.CurrencyService(`localhost:${PORT}`, 30 | grpc.credentials.createInsecure()); 31 | 32 | const logger = pino({ 33 | name: 'currencyservice-client', 34 | messageKey: 'message', 35 | changeLevelName: 'severity', 36 | useLevelLabels: true 37 | }); 38 | 39 | const request = { 40 | from: { 41 | currency_code: 'CHF', 42 | units: 300, 43 | nanos: 0 44 | }, 45 | to_code: 'EUR' 46 | }; 47 | 48 | function _moneyToString (m) { 49 | return `${m.units}.${m.nanos.toString().padStart(9,'0')} ${m.currency_code}`; 50 | } 51 | 52 | client.getSupportedCurrencies({}, (err, response) => { 53 | if (err) { 54 | logger.error(`Error in getSupportedCurrencies: ${err}`); 55 | } else { 56 | logger.info(`Currency codes: ${response.currency_codes}`); 57 | } 58 | }); 59 | 60 | client.convert(request, (err, response) => { 61 | if (err) { 62 | logger.error(`Error in convert: ${err}`); 63 | } else { 64 | logger.log(`Convert: ${_moneyToString(request.from)} to ${_moneyToString(response)}`); 65 | } 66 | }); 67 | -------------------------------------------------------------------------------- /microservices-demo/src/currencyservice/data/currency_conversion.json: -------------------------------------------------------------------------------- 1 | { 2 | "EUR": "1.0", 3 | "USD": "1.1305", 4 | "JPY": "126.40", 5 | "BGN": "1.9558", 6 | "CZK": "25.592", 7 | "DKK": "7.4609", 8 | "GBP": "0.85970", 9 | "HUF": "315.51", 10 | "PLN": "4.2996", 11 | "RON": "4.7463", 12 | "SEK": "10.5375", 13 | "CHF": "1.1360", 14 | "ISK": "136.80", 15 | "NOK": "9.8040", 16 | "HRK": "7.4210", 17 | "RUB": "74.4208", 18 | "TRY": "6.1247", 19 | "AUD": "1.6072", 20 | "BRL": "4.2682", 21 | "CAD": "1.5128", 22 | "CNY": "7.5857", 23 | "HKD": "8.8743", 24 | "IDR": "15999.40", 25 | "ILS": "4.0875", 26 | "INR": "79.4320", 27 | "KRW": "1275.05", 28 | "MXN": "21.7999", 29 | "MYR": "4.6289", 30 | "NZD": "1.6679", 31 | "PHP": "59.083", 32 | "SGD": "1.5349", 33 | "THB": "36.012", 34 | "ZAR": "16.0583" 35 | } -------------------------------------------------------------------------------- /microservices-demo/src/currencyservice/genproto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # [START gke_currencyservice_genproto] 18 | 19 | # protos are loaded dynamically for node, simply copies over the proto. 20 | mkdir -p proto 21 | cp -r ../../pb/* ./proto 22 | 23 | # [END gke_currencyservice_genproto] -------------------------------------------------------------------------------- /microservices-demo/src/currencyservice/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grpc-currency-service", 3 | "version": "0.1.0", 4 | "description": "A gRPC currency conversion microservice", 5 | "repository": "https://github.com/GoogleCloudPlatform/microservices-demo", 6 | "scripts": { 7 | "test": "echo \"Warn: no test specified\" && exit 0", 8 | "lint": "semistandard *.js" 9 | }, 10 | "license": "Apache-2.0", 11 | "dependencies": { 12 | "@google-cloud/debug-agent": "5.2.9", 13 | "@google-cloud/profiler": "4.2.0", 14 | "@google-cloud/trace-agent": "5.1.6", 15 | "@grpc/grpc-js": "1.6.11", 16 | "@grpc/proto-loader": "0.6.13", 17 | "async": "3.2.4", 18 | "google-protobuf": "3.20.1", 19 | "pino": "5.17.0", 20 | "request": "2.88.2", 21 | "xml2js": "0.4.23" 22 | }, 23 | "devDependencies": { 24 | "semistandard": "16.0.1" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /microservices-demo/src/currencyservice/proto/grpc/health/v1/health.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The gRPC Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // The canonical version of this proto can be found at 16 | // https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto 17 | 18 | syntax = "proto3"; 19 | 20 | package grpc.health.v1; 21 | 22 | option csharp_namespace = "Grpc.Health.V1"; 23 | option go_package = "google.golang.org/grpc/health/grpc_health_v1"; 24 | option java_multiple_files = true; 25 | option java_outer_classname = "HealthProto"; 26 | option java_package = "io.grpc.health.v1"; 27 | 28 | message HealthCheckRequest { 29 | string service = 1; 30 | } 31 | 32 | message HealthCheckResponse { 33 | enum ServingStatus { 34 | UNKNOWN = 0; 35 | SERVING = 1; 36 | NOT_SERVING = 2; 37 | } 38 | ServingStatus status = 1; 39 | } 40 | 41 | service Health { 42 | rpc Check(HealthCheckRequest) returns (HealthCheckResponse); 43 | } 44 | -------------------------------------------------------------------------------- /microservices-demo/src/emailservice/.python-version: -------------------------------------------------------------------------------- 1 | 3.7 2 | -------------------------------------------------------------------------------- /microservices-demo/src/emailservice/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM python:3.7-slim as base 16 | 17 | FROM base as builder 18 | 19 | RUN apt-get -qq update \ 20 | && apt-get install -y --no-install-recommends \ 21 | g++ \ 22 | && rm -rf /var/lib/apt/lists/* 23 | 24 | # get packages 25 | COPY requirements.txt . 26 | RUN pip install -r requirements.txt 27 | 28 | FROM base as final 29 | # Enable unbuffered logging 30 | ENV PYTHONUNBUFFERED=1 31 | # Enable Profiler 32 | ENV ENABLE_PROFILER=1 33 | 34 | RUN apt-get -qq update \ 35 | && apt-get install -y --no-install-recommends \ 36 | wget 37 | 38 | # Download the grpc health probe 39 | RUN GRPC_HEALTH_PROBE_VERSION=v0.4.11 && \ 40 | wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ 41 | chmod +x /bin/grpc_health_probe 42 | 43 | WORKDIR /email_server 44 | 45 | # Grab packages from builder 46 | COPY --from=builder /usr/local/lib/python3.7/ /usr/local/lib/python3.7/ 47 | 48 | # Add the application 49 | COPY . . 50 | 51 | EXPOSE 8080 52 | ENTRYPOINT [ "python", "email_server.py" ] 53 | -------------------------------------------------------------------------------- /microservices-demo/src/emailservice/Procfile: -------------------------------------------------------------------------------- 1 | web: python email_server.py 2 | -------------------------------------------------------------------------------- /microservices-demo/src/emailservice/email_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import grpc 18 | 19 | import demo_pb2 20 | import demo_pb2_grpc 21 | 22 | from logger import getJSONLogger 23 | logger = getJSONLogger('emailservice-client') 24 | 25 | from opencensus.trace.tracer import Tracer 26 | from opencensus.trace.exporters import stackdriver_exporter 27 | from opencensus.trace.ext.grpc import client_interceptor 28 | 29 | try: 30 | exporter = stackdriver_exporter.StackdriverExporter() 31 | tracer = Tracer(exporter=exporter) 32 | tracer_interceptor = client_interceptor.OpenCensusClientInterceptor(tracer, host_port='0.0.0.0:8080') 33 | except: 34 | tracer_interceptor = client_interceptor.OpenCensusClientInterceptor() 35 | 36 | def send_confirmation_email(email, order): 37 | channel = grpc.insecure_channel('0.0.0.0:8080') 38 | channel = grpc.intercept_channel(channel, tracer_interceptor) 39 | stub = demo_pb2_grpc.EmailServiceStub(channel) 40 | try: 41 | response = stub.SendOrderConfirmation(demo_pb2.SendOrderConfirmationRequest( 42 | email = email, 43 | order = order 44 | )) 45 | logger.info('Request sent.') 46 | except grpc.RpcError as err: 47 | logger.error(err.details()) 48 | logger.error('{}, {}'.format(err.code().name, err.code().value)) 49 | 50 | if __name__ == '__main__': 51 | logger.info('Client for email service.') 52 | -------------------------------------------------------------------------------- /microservices-demo/src/emailservice/genproto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # [START gke_emailservice_genproto] 18 | 19 | python -m grpc_tools.protoc -I../../pb --python_out=. --grpc_python_out=. ../../pb/demo.proto 20 | 21 | # [END gke_emailservice_genproto] -------------------------------------------------------------------------------- /microservices-demo/src/emailservice/logger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import logging 18 | import sys 19 | from pythonjsonlogger import jsonlogger 20 | 21 | # TODO(yoshifumi) this class is duplicated since other Python services are 22 | # not sharing the modules for logging. 23 | class CustomJsonFormatter(jsonlogger.JsonFormatter): 24 | def add_fields(self, log_record, record, message_dict): 25 | super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict) 26 | if not log_record.get('timestamp'): 27 | log_record['timestamp'] = record.created 28 | if log_record.get('severity'): 29 | log_record['severity'] = log_record['severity'].upper() 30 | else: 31 | log_record['severity'] = record.levelname 32 | 33 | def getJSONLogger(name): 34 | logger = logging.getLogger(name) 35 | handler = logging.StreamHandler(sys.stdout) 36 | formatter = CustomJsonFormatter('(timestamp) (severity) (name) (message)') 37 | handler.setFormatter(formatter) 38 | logger.addHandler(handler) 39 | logger.setLevel(logging.INFO) 40 | logger.propagate = False 41 | return logger 42 | -------------------------------------------------------------------------------- /microservices-demo/src/emailservice/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | testpaths = tests 3 | console_output_style = classic 4 | -------------------------------------------------------------------------------- /microservices-demo/src/emailservice/requirements.in: -------------------------------------------------------------------------------- 1 | google-api-core==2.8.2 2 | grpcio-health-checking==1.47.0 3 | grpcio==1.47.0 4 | jinja2==3.1.2 5 | opencensus==0.9.0 6 | opencensus-ext-stackdriver==0.8.0 7 | opencensus-ext-grpc==0.7.2 8 | python-json-logger==2.0.4 9 | google-cloud-profiler==4.0.0 10 | google-cloud-trace==0.24.2 11 | requests==2.28.1 12 | protobuf==3.20.1 # transitive dependency, move when google-api is bumped safely 13 | pytest==7.1.3 14 | -------------------------------------------------------------------------------- /microservices-demo/src/emailservice/templates/confirmation.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | Your Order Confirmation 21 | 22 | 23 | 28 | 29 |

Your Order Confirmation

30 |

Thanks for shopping with us!

31 |

Order ID

32 |

#{{ order.order_id }}

33 |

Shipping

34 |

#{{ order.shipping_tracking_id }}

35 |

{{ order.shipping_cost.units }}. {{ "%02d" | format(order.shipping_cost.nanos // 10000000) }} {{ order.shipping_cost.currency_code }}

36 |

{{ order.shipping_address.street_address_1 }}, {{order.shipping_address.street_address_2}}, {{order.shipping_address.city}}, {{order.shipping_address.country}} {{order.shipping_address.zip_code}}

37 |

Items

38 | 39 | 40 | 41 | 42 | 43 | 44 | {% for item in order.items %} 45 | 46 | 47 | 48 | 49 | 50 | {% endfor %} 51 |
Item No.QuantityPrice
#{{ item.item.product_id }}{{ item.item.quantity }}{{ item.cost.units }}.{{ "%02d" | format(item.cost.nanos // 10000000) }} {{ item.cost.currency_code }}
52 | 53 | 54 | -------------------------------------------------------------------------------- /microservices-demo/src/emailservice/tests/test_sample.py: -------------------------------------------------------------------------------- 1 | def func(x): 2 | return x + 1 3 | 4 | 5 | def test_answer(): 6 | assert func(3) == 4 7 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/.dockerignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/.gitkeep -------------------------------------------------------------------------------- /microservices-demo/src/frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM golang:1.18.4-alpine as builder 16 | RUN apk add --no-cache ca-certificates git 17 | RUN apk add build-base 18 | WORKDIR /src 19 | 20 | # restore dependencies 21 | COPY go.mod go.sum ./ 22 | RUN go mod download 23 | COPY . . 24 | 25 | # Skaffold passes in debug-oriented compiler flags 26 | ARG SKAFFOLD_GO_GCFLAGS 27 | RUN go build -gcflags="${SKAFFOLD_GO_GCFLAGS}" -o /go/bin/frontend . 28 | 29 | FROM alpine as release 30 | RUN apk add --no-cache ca-certificates \ 31 | busybox-extras net-tools bind-tools 32 | WORKDIR /src 33 | COPY --from=builder /go/bin/frontend /src/server 34 | COPY ./templates ./templates 35 | COPY ./static ./static 36 | 37 | # Definition of this variable is used by 'skaffold debug' to identify a golang binary. 38 | # Default behavior - a failure prints a stack trace for the current goroutine. 39 | # See https://golang.org/pkg/runtime/ 40 | ENV GOTRACEBACK=single 41 | 42 | EXPOSE 8080 43 | ENTRYPOINT ["/src/server"] 44 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/README.md: -------------------------------------------------------------------------------- 1 | # frontend 2 | 3 | Run the following command to restore dependencies to `vendor/` directory: 4 | 5 | dep ensure --vendor-only 6 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/deployment_details.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | "os" 6 | "time" 7 | 8 | "cloud.google.com/go/compute/metadata" 9 | "github.com/sirupsen/logrus" 10 | ) 11 | 12 | var deploymentDetailsMap map[string]string 13 | var log *logrus.Logger 14 | 15 | func init() { 16 | initializeLogger() 17 | // Use a goroutine to ensure loadDeploymentDetails()'s GCP API 18 | // calls don't block non-GCP deployments. See issue #685. 19 | go loadDeploymentDetails() 20 | } 21 | 22 | func initializeLogger() { 23 | log = logrus.New() 24 | log.Level = logrus.DebugLevel 25 | log.Formatter = &logrus.JSONFormatter{ 26 | FieldMap: logrus.FieldMap{ 27 | logrus.FieldKeyTime: "timestamp", 28 | logrus.FieldKeyLevel: "severity", 29 | logrus.FieldKeyMsg: "message", 30 | }, 31 | TimestampFormat: time.RFC3339Nano, 32 | } 33 | log.Out = os.Stdout 34 | } 35 | 36 | func loadDeploymentDetails() { 37 | deploymentDetailsMap = make(map[string]string) 38 | var metaServerClient = metadata.NewClient(&http.Client{}) 39 | 40 | podHostname, err := os.Hostname() 41 | if err != nil { 42 | log.Error("Failed to fetch the hostname for the Pod", err) 43 | } 44 | 45 | podCluster, err := metaServerClient.InstanceAttributeValue("cluster-name") 46 | if err != nil { 47 | log.Error("Failed to fetch the name of the cluster in which the pod is running", err) 48 | } 49 | 50 | podZone, err := metaServerClient.Zone() 51 | if err != nil { 52 | log.Error("Failed to fetch the Zone of the node where the pod is scheduled", err) 53 | } 54 | 55 | deploymentDetailsMap["HOSTNAME"] = podHostname 56 | deploymentDetailsMap["CLUSTERNAME"] = podCluster 57 | deploymentDetailsMap["ZONE"] = podZone 58 | 59 | log.WithFields(logrus.Fields{ 60 | "cluster": podCluster, 61 | "zone": podZone, 62 | "hostname": podHostname, 63 | }).Debug("Loaded deployment details") 64 | } 65 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/genproto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # [START gke_frontend_genproto] 18 | 19 | PATH=$PATH:$GOPATH/bin 20 | protodir=../../pb 21 | 22 | protoc --go_out=plugins=grpc:genproto -I $protodir $protodir/demo.proto 23 | 24 | # [END gke_frontend_genproto] -------------------------------------------------------------------------------- /microservices-demo/src/frontend/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/GoogleCloudPlatform/microservices-demo/src/frontend 2 | 3 | go 1.18 4 | 5 | require ( 6 | cloud.google.com/go v0.104.0 7 | cloud.google.com/go/compute v1.7.0 8 | cloud.google.com/go/profiler v0.3.0 9 | contrib.go.opencensus.io/exporter/jaeger v0.2.1 10 | contrib.go.opencensus.io/exporter/stackdriver v0.13.12 11 | github.com/golang/protobuf v1.5.2 12 | github.com/google/uuid v1.3.0 13 | github.com/gorilla/mux v1.8.0 14 | github.com/pkg/errors v0.9.1 15 | github.com/sirupsen/logrus v1.8.1 16 | go.opencensus.io v0.23.0 17 | golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b 18 | google.golang.org/grpc v1.48.0 19 | ) 20 | 21 | require ( 22 | cloud.google.com/go/monitoring v1.1.0 // indirect 23 | cloud.google.com/go/trace v1.0.0 // indirect 24 | github.com/aws/aws-sdk-go v1.43.31 // indirect 25 | github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect 26 | github.com/cespare/xxhash/v2 v2.1.1 // indirect 27 | github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect 28 | github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 // indirect 29 | github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect 30 | github.com/envoyproxy/protoc-gen-validate v0.1.0 // indirect 31 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 32 | github.com/google/go-cmp v0.5.8 // indirect 33 | github.com/google/pprof v0.0.0-20220412212628-83db2b799d1f // indirect 34 | github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect 35 | github.com/googleapis/gax-go/v2 v2.4.0 // indirect 36 | github.com/jmespath/go-jmespath v0.4.0 // indirect 37 | github.com/prometheus/prometheus v2.5.0+incompatible // indirect 38 | github.com/uber/jaeger-client-go v2.25.0+incompatible // indirect 39 | golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 // indirect 40 | golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect 41 | golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect 42 | golang.org/x/text v0.3.7 // indirect 43 | google.golang.org/api v0.93.0 // indirect 44 | google.golang.org/appengine v1.6.7 // indirect 45 | google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // indirect 46 | google.golang.org/protobuf v1.28.1 // indirect 47 | ) 48 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/middleware.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "context" 19 | "net/http" 20 | "time" 21 | 22 | "github.com/google/uuid" 23 | "github.com/sirupsen/logrus" 24 | ) 25 | 26 | type ctxKeyLog struct{} 27 | type ctxKeyRequestID struct{} 28 | 29 | type logHandler struct { 30 | log *logrus.Logger 31 | next http.Handler 32 | } 33 | 34 | type responseRecorder struct { 35 | b int 36 | status int 37 | w http.ResponseWriter 38 | } 39 | 40 | func (r *responseRecorder) Header() http.Header { return r.w.Header() } 41 | 42 | func (r *responseRecorder) Write(p []byte) (int, error) { 43 | if r.status == 0 { 44 | r.status = http.StatusOK 45 | } 46 | n, err := r.w.Write(p) 47 | r.b += n 48 | return n, err 49 | } 50 | 51 | func (r *responseRecorder) WriteHeader(statusCode int) { 52 | r.status = statusCode 53 | r.w.WriteHeader(statusCode) 54 | } 55 | 56 | func (lh *logHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 57 | ctx := r.Context() 58 | requestID, _ := uuid.NewRandom() 59 | ctx = context.WithValue(ctx, ctxKeyRequestID{}, requestID.String()) 60 | 61 | start := time.Now() 62 | rr := &responseRecorder{w: w} 63 | log := lh.log.WithFields(logrus.Fields{ 64 | "http.req.path": r.URL.Path, 65 | "http.req.method": r.Method, 66 | "http.req.id": requestID.String(), 67 | }) 68 | if v, ok := r.Context().Value(ctxKeySessionID{}).(string); ok { 69 | log = log.WithField("session", v) 70 | } 71 | log.Debug("request started") 72 | defer func() { 73 | log.WithFields(logrus.Fields{ 74 | "http.resp.took_ms": int64(time.Since(start) / time.Millisecond), 75 | "http.resp.status": rr.status, 76 | "http.resp.bytes": rr.b}).Debugf("request complete") 77 | }() 78 | 79 | ctx = context.WithValue(ctx, ctxKeyLog{}, log) 80 | r = r.WithContext(ctx) 81 | lh.next.ServeHTTP(rr, r) 82 | } 83 | 84 | func ensureSessionID(next http.Handler) http.HandlerFunc { 85 | return func(w http.ResponseWriter, r *http.Request) { 86 | var sessionID string 87 | c, err := r.Cookie(cookieSessionID) 88 | if err == http.ErrNoCookie { 89 | u, _ := uuid.NewRandom() 90 | sessionID = u.String() 91 | http.SetCookie(w, &http.Cookie{ 92 | Name: cookieSessionID, 93 | Value: sessionID, 94 | MaxAge: cookieMaxAge, 95 | }) 96 | } else if err != nil { 97 | return 98 | } else { 99 | sessionID = c.Value 100 | } 101 | ctx := context.WithValue(r.Context(), ctxKeySessionID{}, sessionID) 102 | r = r.WithContext(ctx) 103 | next.ServeHTTP(w, r) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/favicon-cymbal.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/favicon-cymbal.ico -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/favicon.ico -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/icons/Hipster_CartIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | Hipster 27 | 28 | 29 | 30 | 54 | 56 | 58 | 59 | Hipster 61 | 64 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/icons/Hipster_CheckOutIcon.svg: -------------------------------------------------------------------------------- 1 | Hipster -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/icons/Hipster_CurrencyIcon.svg: -------------------------------------------------------------------------------- 1 | Hipster -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/icons/Hipster_DownArrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 18 | 19 | 21 | image/svg+xml 22 | 24 | 25 | 26 | 27 | 47 | 49 | 51 | 52 | Hipster 54 | 57 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/icons/Hipster_FacebookIcon.svg: -------------------------------------------------------------------------------- 1 | Hipster -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/icons/Hipster_HelpIcon.svg: -------------------------------------------------------------------------------- 1 | Hipster -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/icons/Hipster_InstagramIcon.svg: -------------------------------------------------------------------------------- 1 | Hipster -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/icons/Hipster_PinterestIcon.svg: -------------------------------------------------------------------------------- 1 | Hipster -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/icons/Hipster_ProfileIcon.svg: -------------------------------------------------------------------------------- 1 | Hipster -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/icons/Hipster_SearchIcon.svg: -------------------------------------------------------------------------------- 1 | Hipster -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/icons/Hipster_TwitterIcon.svg: -------------------------------------------------------------------------------- 1 | Hipster -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/icons/Hipster_UpDownControl.svg: -------------------------------------------------------------------------------- 1 | 2 | Hipster 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/icons/Hipster_YoutubeIcon.svg: -------------------------------------------------------------------------------- 1 | Hipster -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/images/Advert2BannerImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/images/Advert2BannerImage.png -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/images/AdvertBannerImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/images/AdvertBannerImage.png -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/images/HeroBannerImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/images/HeroBannerImage.png -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/images/HeroBannerImage2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/images/HeroBannerImage2.png -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/images/VRHeadsets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/images/VRHeadsets.png -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/images/credits.txt: -------------------------------------------------------------------------------- 1 | folded-clothes-on-white-chair.jpg,,https://unsplash.com/photos/fr0J5-GIVyg 2 | folded-clothes-on-white-chair-wide.jpg,,https://unsplash.com/photos/fr0J5-GIVyg 3 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/images/folded-clothes-on-white-chair-wide.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/images/folded-clothes-on-white-chair-wide.jpg -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/images/folded-clothes-on-white-chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/images/folded-clothes-on-white-chair.jpg -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/img/products/bamboo-glass-jar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/img/products/bamboo-glass-jar.jpg -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/img/products/candle-holder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/img/products/candle-holder.jpg -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/img/products/hairdryer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/img/products/hairdryer.jpg -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/img/products/loafers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/img/products/loafers.jpg -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/img/products/mug.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/img/products/mug.jpg -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/img/products/salt-and-pepper-shakers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/img/products/salt-and-pepper-shakers.jpg -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/img/products/sunglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/img/products/sunglasses.jpg -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/img/products/tank-top.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/img/products/tank-top.jpg -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/img/products/watch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/microservices-demo/src/frontend/static/img/products/watch.jpg -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/styles/cart.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | .cart-sections { 18 | padding-bottom: 120px; 19 | padding-top: 56px; 20 | background-color: #F9F9F9; 21 | } 22 | 23 | .cart-sections h3 { 24 | font-size: 36px; 25 | font-weight: normal; 26 | } 27 | 28 | .cart-sections a.cymbal-button-primary:hover { 29 | text-decoration: none; 30 | color: white; 31 | } 32 | 33 | /* Empty Cart Section */ 34 | 35 | .empty-cart-section { 36 | max-width: 458px; 37 | margin: auto; 38 | text-align: center; 39 | } 40 | 41 | .empty-cart-section a { 42 | display: inline-block; /* So margin-top works. */ 43 | margin-top: 32px; 44 | } 45 | 46 | .empty-cart-section a:hover { 47 | color: white; 48 | text-decoration: none; 49 | } 50 | 51 | /* Cart Summary Section */ 52 | 53 | .cart-summary-empty-cart-button { 54 | margin-right: 10px; 55 | } 56 | 57 | .cart-summary-item-row, 58 | .cart-summary-shipping-row, 59 | .cart-summary-total-row { 60 | padding-bottom: 24px; 61 | padding-top: 24px; 62 | border-top: solid 1px rgba(154, 160, 166, 0.5); 63 | } 64 | 65 | .cart-summary-item-row img { 66 | border-radius: 20% 0 20% 20%; 67 | } 68 | 69 | .cart-summary-item-row-item-id-row { 70 | font-size: 12px; 71 | color: #5C6063; 72 | } 73 | 74 | .cart-summary-item-row h4 { 75 | font-size: 18px; 76 | font-weight: normal; 77 | } 78 | 79 | /* Stick item quantity and cost to the bottom (for wider screens). */ 80 | @media (min-width: 768px) { 81 | .cart-summary-item-row .row:last-child { 82 | position: absolute; 83 | bottom: 0px; 84 | width: 100%; 85 | } 86 | } 87 | 88 | /* Item cost (price). */ 89 | .cart-summary-item-row .row:last-child strong { 90 | font-weight: 500; 91 | } 92 | 93 | .cart-summary-total-row { 94 | font-size: 28px; 95 | } 96 | 97 | /* Cart Checkout Form */ 98 | 99 | .cart-checkout-form h3 { 100 | margin-bottom: 0; 101 | } 102 | 103 | .payment-method-heading { 104 | margin-top: 36px; 105 | } 106 | 107 | /* "Place Order" button */ 108 | .cart-checkout-form .cymbal-button-primary { 109 | margin-top: 36px; 110 | } -------------------------------------------------------------------------------- /microservices-demo/src/frontend/static/styles/order.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | .order { 18 | background: #F9F9F9; 19 | } 20 | 21 | .order-complete-section { 22 | max-width: 487px; 23 | padding-top: 56px; 24 | padding-bottom: 120px; 25 | } 26 | 27 | .order-complete-section h3 { 28 | margin: 0; 29 | font-size: 36px; 30 | font-weight: normal; 31 | } 32 | 33 | .order-complete-section p { 34 | margin-top: 8px; 35 | } 36 | 37 | .order-complete-section .padding-y-24 { 38 | padding-bottom: 24px; 39 | padding-top: 24px; 40 | } 41 | 42 | .order-complete-section .border-bottom-solid { 43 | border-bottom: 1px solid rgba(154, 160, 166, 0.5); 44 | } 45 | 46 | .order-complete-section .cymbal-button-primary { 47 | margin-top: 24px; 48 | } 49 | 50 | .order-complete-section a.cymbal-button-primary:hover { 51 | text-decoration: none; 52 | color: white; 53 | } 54 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/templates/ad.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | {{ define "text_ad" }} 18 |
19 |
20 | Ad 21 | 22 | {{.Text}} 23 | 24 |
25 |
26 | {{ end }} -------------------------------------------------------------------------------- /microservices-demo/src/frontend/templates/error.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | {{ define "error" }} 18 | {{ template "header" . }} 19 |
20 | 21 | {{$.platform_name}} 22 | 23 |
24 |
25 |
26 |
27 |

Uh, oh!

28 |

Something has failed. Below are some details for debugging.

29 | 30 |

HTTP Status: {{.status_code}} {{.status}}

31 |
33 |                     {{- .error -}}
34 |                 
35 |
36 |
37 |
38 | 39 | {{ template "footer" . }} 40 | {{ end }} -------------------------------------------------------------------------------- /microservices-demo/src/frontend/templates/footer.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | {{ define "footer" }} 18 | 19 |
20 | 49 |
50 | 53 | 54 | 55 | 56 | {{ end }} 57 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/templates/home.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | {{ define "home" }} 18 | 19 | {{ template "header" . }} 20 |
21 | 22 | {{$.platform_name}} 23 | 24 |
25 |
26 | 27 | 28 |
29 | 30 |
31 |
32 | 33 | 34 |
35 | 36 |
37 | 38 |
39 | 40 |
41 |

Hot Products

42 |
43 | 44 | {{ range $.products }} 45 |
46 | 47 | 48 |
49 |
50 |
51 |
{{ .Item.Name }}
52 |
{{ renderMoney .Price }}
53 |
54 |
55 | {{ end }} 56 | 57 |
58 | 59 | 60 | 65 | 66 |
67 | 68 |
69 |
70 | 71 |
72 | 73 | 74 |
75 | {{ template "footer" . }} 76 |
77 | 78 | {{ end }} 79 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/templates/order.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | {{ define "order" }} 18 | 19 | {{ template "header" . }} 20 | 21 |
22 | 23 | {{$.platform_name}} 24 | 25 |
26 | 27 |
28 | 29 |
30 |
31 |
32 |

33 | Your order is complete! 34 |

35 |
36 |
37 |

We've sent you a confirmation email.

38 |
39 |
40 |
41 |
42 | Confirmation # 43 |
44 |
45 | {{.order.OrderId}} 46 |
47 |
48 |
49 |
50 | Tracking # 51 |
52 |
53 | {{.order.ShippingTrackingId}} 54 |
55 |
56 |
57 |
58 | Total Paid 59 |
60 |
61 | {{renderMoney .total_paid}} 62 |
63 |
64 |
65 | 70 |
71 |
72 | 73 | {{ if $.recommendations }} 74 | {{ template "recommendations" $.recommendations }} 75 | {{ end }} 76 | 77 |
78 | 79 | {{ template "footer" . }} 80 | {{ end }} 81 | -------------------------------------------------------------------------------- /microservices-demo/src/frontend/templates/product.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | {{ define "product" }} 18 | {{ template "header" . }} 19 |
20 | 21 | {{$.platform_name}} 22 | 23 |
24 | 25 |
26 |
27 |
28 |
29 | 30 |
31 |
32 |
33 | 34 |

{{ $.product.Item.Name }}

35 |

{{ renderMoney $.product.Price }}

36 |

{{ $.product.Item.Description }}

37 | 38 |
39 | 40 |
41 | 49 | 50 |
51 | 52 |
53 |
54 |
55 |
56 |
57 |
58 | {{ if $.recommendations}} 59 | {{ template "recommendations" $.recommendations }} 60 | {{ end }} 61 |
62 |
63 | {{ with $.ad }}{{ template "text_ad" . }}{{ end }} 64 |
65 |
66 | {{ template "footer" . }} 67 | {{ end }} -------------------------------------------------------------------------------- /microservices-demo/src/frontend/templates/recommendations.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | {{ define "recommendations" }} 18 |
19 |
20 |
21 |
22 |

You May Also Like

23 |
24 | {{range . }} 25 |
26 |
27 | 28 | 29 | 30 |
31 |
32 | {{ .Name }} 33 |
34 |
35 |
36 |
37 | {{ end }} 38 |
39 |
40 |
41 |
42 |
43 | {{ end }} -------------------------------------------------------------------------------- /microservices-demo/src/loadgenerator/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM python:3.9-slim as base 16 | 17 | FROM base as builder 18 | 19 | RUN apt-get -qq update \ 20 | && apt-get install -y --no-install-recommends \ 21 | g++ 22 | 23 | COPY requirements.txt . 24 | 25 | RUN pip install --prefix="/install" -r requirements.txt 26 | 27 | FROM base 28 | 29 | WORKDIR /loadgen 30 | 31 | COPY --from=builder /install /usr/local 32 | 33 | # Add application code. 34 | COPY locustfile.py . 35 | 36 | # enable gevent support in debugger 37 | ENV GEVENT_SUPPORT=True 38 | 39 | ENTRYPOINT locust --host="http://${FRONTEND_ADDR}" --headless -u "${USERS:-10}" 2>&1 40 | -------------------------------------------------------------------------------- /microservices-demo/src/loadgenerator/loadgenerator.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | apiVersion: apps/v1 15 | kind: Deployment 16 | metadata: 17 | name: loadgenerator 18 | spec: 19 | selector: 20 | matchLabels: 21 | app: loadgenerator 22 | replicas: 1 23 | template: 24 | metadata: 25 | labels: 26 | app: loadgenerator 27 | annotations: 28 | sidecar.istio.io/rewriteAppHTTPProbers: "true" 29 | spec: 30 | serviceAccountName: default 31 | terminationGracePeriodSeconds: 5 32 | restartPolicy: Always 33 | securityContext: 34 | fsGroup: 1000 35 | runAsGroup: 1000 36 | runAsNonRoot: true 37 | runAsUser: 1000 38 | initContainers: 39 | - command: 40 | - /bin/sh 41 | - -exc 42 | - | 43 | echo "Init container pinging frontend: ${FRONTEND_ADDR}..." 44 | STATUSCODE=$(wget --server-response http://${FRONTEND_ADDR} 2>&1 | awk '/^ HTTP/{print $2}') 45 | if test $STATUSCODE -ne 200; then 46 | echo "Error: Could not reach frontend - Status code: ${STATUSCODE}" 47 | exit 1 48 | fi 49 | name: frontend-check 50 | securityContext: 51 | allowPrivilegeEscalation: false 52 | capabilities: 53 | drop: 54 | - all 55 | privileged: false 56 | readOnlyRootFilesystem: true 57 | image: busybox:latest 58 | env: 59 | - name: FRONTEND_ADDR 60 | value: "frontend:80" 61 | containers: 62 | - name: main 63 | securityContext: 64 | allowPrivilegeEscalation: false 65 | capabilities: 66 | drop: 67 | - all 68 | privileged: false 69 | readOnlyRootFilesystem: true 70 | image: 71 | env: 72 | - name: FRONTEND_ADDR 73 | value: "frontend:80" 74 | - name: USERS 75 | value: "10" 76 | resources: 77 | requests: 78 | cpu: 300m 79 | memory: 256Mi 80 | limits: 81 | cpu: 500m 82 | memory: 512Mi 83 | -------------------------------------------------------------------------------- /microservices-demo/src/loadgenerator/locustfile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import random 18 | from locust import HttpUser, TaskSet, between 19 | 20 | products = [ 21 | '0PUK6V6EV0', 22 | '1YMWWN1N4O', 23 | '2ZYFJ3GM2N', 24 | '66VCHSJNUP', 25 | '6E92ZMYYFZ', 26 | '9SIQT8TOJO', 27 | 'L9ECAV7KIM', 28 | 'LS4PSXUNUM', 29 | 'OLJCESPC7Z'] 30 | 31 | def index(l): 32 | l.client.get("/") 33 | 34 | def setCurrency(l): 35 | currencies = ['EUR', 'USD', 'JPY', 'CAD'] 36 | l.client.post("/setCurrency", 37 | {'currency_code': random.choice(currencies)}) 38 | 39 | def browseProduct(l): 40 | l.client.get("/product/" + random.choice(products)) 41 | 42 | def viewCart(l): 43 | l.client.get("/cart") 44 | 45 | def addToCart(l): 46 | product = random.choice(products) 47 | l.client.get("/product/" + product) 48 | l.client.post("/cart", { 49 | 'product_id': product, 50 | 'quantity': random.choice([1,2,3,4,5,10])}) 51 | 52 | def checkout(l): 53 | addToCart(l) 54 | l.client.post("/cart/checkout", { 55 | 'email': 'someone@example.com', 56 | 'street_address': '1600 Amphitheatre Parkway', 57 | 'zip_code': '94043', 58 | 'city': 'Mountain View', 59 | 'state': 'CA', 60 | 'country': 'United States', 61 | 'credit_card_number': '4432-8015-6152-0454', 62 | 'credit_card_expiration_month': '1', 63 | 'credit_card_expiration_year': '2039', 64 | 'credit_card_cvv': '672', 65 | }) 66 | 67 | class UserBehavior(TaskSet): 68 | 69 | def on_start(self): 70 | index(self) 71 | 72 | tasks = {index: 1, 73 | setCurrency: 2, 74 | browseProduct: 10, 75 | addToCart: 2, 76 | viewCart: 3, 77 | checkout: 1} 78 | 79 | class WebsiteUser(HttpUser): 80 | tasks = [UserBehavior] 81 | wait_time = between(1, 10) 82 | -------------------------------------------------------------------------------- /microservices-demo/src/loadgenerator/requirements.in: -------------------------------------------------------------------------------- 1 | locust==2.12.1 2 | -------------------------------------------------------------------------------- /microservices-demo/src/loadgenerator/requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with python 3.9 3 | # To update, run: 4 | # 5 | # pip-compile --output-file=requirements.txt requirements.in 6 | # 7 | brotli==1.0.9 8 | # via geventhttpclient 9 | certifi==2022.9.24 10 | # via 11 | # geventhttpclient 12 | # requests 13 | charset-normalizer==2.1.1 14 | # via requests 15 | click==8.1.3 16 | # via flask 17 | configargparse==1.5.3 18 | # via locust 19 | flask==2.2.2 20 | # via 21 | # flask-basicauth 22 | # flask-cors 23 | # locust 24 | flask-basicauth==0.2.0 25 | # via locust 26 | flask-cors==3.0.10 27 | # via locust 28 | gevent==21.12.0 29 | # via 30 | # geventhttpclient 31 | # locust 32 | geventhttpclient==2.0.2 33 | # via locust 34 | greenlet==1.1.3 35 | # via gevent 36 | idna==3.4 37 | # via requests 38 | importlib-metadata==5.0.0 39 | # via flask 40 | itsdangerous==2.1.2 41 | # via flask 42 | jinja2==3.1.2 43 | # via flask 44 | locust==2.12.1 45 | # via -r requirements.in 46 | markupsafe==2.1.1 47 | # via 48 | # jinja2 49 | # werkzeug 50 | msgpack==1.0.4 51 | # via locust 52 | psutil==5.9.2 53 | # via locust 54 | pyzmq==24.0.1 55 | # via locust 56 | requests==2.28.1 57 | # via locust 58 | roundrobin==0.0.4 59 | # via locust 60 | six==1.16.0 61 | # via 62 | # flask-cors 63 | # geventhttpclient 64 | typing-extensions==4.3.0 65 | # via locust 66 | urllib3==1.26.12 67 | # via requests 68 | werkzeug==2.2.2 69 | # via 70 | # flask 71 | # locust 72 | zipp==3.8.1 73 | # via importlib-metadata 74 | zope-event==4.5.0 75 | # via gevent 76 | zope-interface==5.4.0 77 | # via gevent 78 | 79 | # The following packages are considered to be unsafe in a requirements file: 80 | # setuptools 81 | -------------------------------------------------------------------------------- /microservices-demo/src/paymentservice/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /microservices-demo/src/paymentservice/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /microservices-demo/src/paymentservice/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM node:18-alpine as base 16 | 17 | FROM base as builder 18 | 19 | # Some packages (e.g. @google-cloud/profiler) require additional 20 | # deps for post-install scripts 21 | RUN apk add --update --no-cache \ 22 | python3 \ 23 | make \ 24 | g++ 25 | 26 | WORKDIR /usr/src/app 27 | 28 | COPY package*.json ./ 29 | 30 | RUN npm install --only=production 31 | 32 | FROM base 33 | 34 | RUN GRPC_HEALTH_PROBE_VERSION=v0.4.11 && \ 35 | wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ 36 | chmod +x /bin/grpc_health_probe 37 | 38 | WORKDIR /usr/src/app 39 | 40 | COPY --from=builder /usr/src/app/node_modules ./node_modules 41 | 42 | COPY . . 43 | 44 | EXPOSE 50051 45 | 46 | ENTRYPOINT [ "node", "index.js" ] 47 | -------------------------------------------------------------------------------- /microservices-demo/src/paymentservice/charge.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | const cardValidator = require('simple-card-validator'); 16 | const uuid = require('uuid/v4'); 17 | const pino = require('pino'); 18 | 19 | const logger = pino({ 20 | name: 'paymentservice-charge', 21 | messageKey: 'message', 22 | changeLevelName: 'severity', 23 | useLevelLabels: true 24 | }); 25 | 26 | 27 | class CreditCardError extends Error { 28 | constructor (message) { 29 | super(message); 30 | this.code = 400; // Invalid argument error 31 | } 32 | } 33 | 34 | class InvalidCreditCard extends CreditCardError { 35 | constructor (cardType) { 36 | super(`Credit card info is invalid`); 37 | } 38 | } 39 | 40 | class UnacceptedCreditCard extends CreditCardError { 41 | constructor (cardType) { 42 | super(`Sorry, we cannot process ${cardType} credit cards. Only VISA or MasterCard is accepted.`); 43 | } 44 | } 45 | 46 | class ExpiredCreditCard extends CreditCardError { 47 | constructor (number, month, year) { 48 | super(`Your credit card (ending ${number.substr(-4)}) expired on ${month}/${year}`); 49 | } 50 | } 51 | 52 | /** 53 | * Verifies the credit card number and (pretend) charges the card. 54 | * 55 | * @param {*} request 56 | * @return transaction_id - a random uuid v4. 57 | */ 58 | module.exports = function charge (request) { 59 | const { amount, credit_card: creditCard } = request; 60 | const cardNumber = creditCard.credit_card_number; 61 | const cardInfo = cardValidator(cardNumber); 62 | const { 63 | card_type: cardType, 64 | valid 65 | } = cardInfo.getCardDetails(); 66 | 67 | if (!valid) { throw new InvalidCreditCard(); } 68 | 69 | // Only VISA and mastercard is accepted, other card types (AMEX, dinersclub) will 70 | // throw UnacceptedCreditCard error. 71 | if (!(cardType === 'visa' || cardType === 'mastercard')) { throw new UnacceptedCreditCard(cardType); } 72 | 73 | // Also validate expiration is > today. 74 | const currentMonth = new Date().getMonth() + 1; 75 | const currentYear = new Date().getFullYear(); 76 | const { credit_card_expiration_year: year, credit_card_expiration_month: month } = creditCard; 77 | if ((currentYear * 12 + currentMonth) > (year * 12 + month)) { throw new ExpiredCreditCard(cardNumber.replace('-', ''), month, year); } 78 | 79 | logger.info(`Transaction processed: ${cardType} ending ${cardNumber.substr(-4)} \ 80 | Amount: ${amount.currency_code}${amount.units}.${amount.nanos}`); 81 | 82 | return { transaction_id: uuid() }; 83 | }; 84 | -------------------------------------------------------------------------------- /microservices-demo/src/paymentservice/genproto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # [START gke_paymentservice_genproto] 18 | 19 | # protos are loaded dynamically for node, simply copies over the proto. 20 | mkdir -p proto 21 | cp -r ../../pb/* ./proto 22 | 23 | # [END gke_paymentservice_genproto] -------------------------------------------------------------------------------- /microservices-demo/src/paymentservice/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | 20 | if(process.env.DISABLE_PROFILER) { 21 | console.log("Profiler disabled.") 22 | } 23 | else { 24 | console.log("Profiler enabled.") 25 | require('@google-cloud/profiler').start({ 26 | serviceContext: { 27 | service: 'paymentservice', 28 | version: '1.0.0' 29 | } 30 | }); 31 | } 32 | 33 | 34 | if(process.env.DISABLE_TRACING) { 35 | console.log("Tracing disabled.") 36 | } 37 | else { 38 | console.log("Tracing enabled.") 39 | require('@google-cloud/trace-agent').start(); 40 | 41 | } 42 | 43 | if(process.env.DISABLE_DEBUGGER) { 44 | console.log("Debugger disabled.") 45 | } 46 | else { 47 | console.log("Debugger enabled.") 48 | require('@google-cloud/debug-agent').start({ 49 | serviceContext: { 50 | service: 'paymentservice', 51 | version: 'VERSION' 52 | } 53 | }); 54 | } 55 | 56 | 57 | const path = require('path'); 58 | const HipsterShopServer = require('./server'); 59 | 60 | const PORT = process.env['PORT']; 61 | const PROTO_PATH = path.join(__dirname, '/proto/'); 62 | 63 | const server = new HipsterShopServer(PROTO_PATH, PORT); 64 | 65 | server.listen(); 66 | -------------------------------------------------------------------------------- /microservices-demo/src/paymentservice/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "paymentservice", 3 | "version": "0.0.1", 4 | "description": "Payment Microservice demo", 5 | "repository": "https://github.com/GoogleCloudPlatform/microservices-demo", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Warn: no test specified\" && exit 0", 9 | "lint": "semistandard *.js" 10 | }, 11 | "author": "Jonathan Lui", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@google-cloud/debug-agent": "5.2.9", 15 | "@google-cloud/profiler": "4.2.0", 16 | "@google-cloud/trace-agent": "5.1.6", 17 | "@grpc/grpc-js": "1.6.11", 18 | "@grpc/proto-loader": "0.6.13", 19 | "pino": "5.17.0", 20 | "simple-card-validator": "^1.1.0", 21 | "uuid": "^3.2.1" 22 | }, 23 | "devDependencies": { 24 | "semistandard": "16.0.1" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /microservices-demo/src/paymentservice/proto/grpc/health/v1/health.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The gRPC Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // The canonical version of this proto can be found at 16 | // https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto 17 | 18 | syntax = "proto3"; 19 | 20 | package grpc.health.v1; 21 | 22 | option csharp_namespace = "Grpc.Health.V1"; 23 | option go_package = "google.golang.org/grpc/health/grpc_health_v1"; 24 | option java_multiple_files = true; 25 | option java_outer_classname = "HealthProto"; 26 | option java_package = "io.grpc.health.v1"; 27 | 28 | message HealthCheckRequest { 29 | string service = 1; 30 | } 31 | 32 | message HealthCheckResponse { 33 | enum ServingStatus { 34 | UNKNOWN = 0; 35 | SERVING = 1; 36 | NOT_SERVING = 2; 37 | } 38 | ServingStatus status = 1; 39 | } 40 | 41 | service Health { 42 | rpc Check(HealthCheckRequest) returns (HealthCheckResponse); 43 | } 44 | -------------------------------------------------------------------------------- /microservices-demo/src/productcatalogservice/.dockerignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | -------------------------------------------------------------------------------- /microservices-demo/src/productcatalogservice/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM golang:1.18.4-alpine AS builder 16 | RUN apk add --no-cache ca-certificates git 17 | RUN apk add build-base 18 | 19 | WORKDIR /src 20 | # restore dependencies 21 | COPY go.mod go.sum ./ 22 | RUN go mod download 23 | COPY . . 24 | 25 | # Skaffold passes in debug-oriented compiler flags 26 | ARG SKAFFOLD_GO_GCFLAGS 27 | RUN go build -gcflags="${SKAFFOLD_GO_GCFLAGS}" -o /productcatalogservice . 28 | 29 | FROM alpine AS release 30 | RUN apk add --no-cache ca-certificates 31 | RUN GRPC_HEALTH_PROBE_VERSION=v0.4.11 && \ 32 | wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ 33 | chmod +x /bin/grpc_health_probe 34 | WORKDIR /src 35 | COPY --from=builder /productcatalogservice ./server 36 | COPY products.json . 37 | 38 | # Definition of this variable is used by 'skaffold debug' to identify a golang binary. 39 | # Default behavior - a failure prints a stack trace for the current goroutine. 40 | # See https://golang.org/pkg/runtime/ 41 | ENV GOTRACEBACK=single 42 | 43 | EXPOSE 3550 44 | ENTRYPOINT ["/src/server"] 45 | 46 | -------------------------------------------------------------------------------- /microservices-demo/src/productcatalogservice/README.md: -------------------------------------------------------------------------------- 1 | # productcatalogservice 2 | 3 | Run the following command to restore dependencies to `vendor/` directory: 4 | 5 | dep ensure --vendor-only 6 | 7 | ## Dynamic catalog reloading / artificial delay 8 | 9 | This service has a "dynamic catalog reloading" feature that is purposefully 10 | not well implemented. The goal of this feature is to allow you to modify the 11 | `products.json` file and have the changes be picked up without having to 12 | restart the service. 13 | 14 | However, this feature is bugged: the catalog is actually reloaded on each 15 | request, introducing a noticeable delay in the frontend. This delay will also 16 | show up in profiling tools: the `parseCatalog` function will take more than 80% 17 | of the CPU time. 18 | 19 | You can trigger this feature (and the delay) by sending a `USR1` signal and 20 | remove it (if needed) by sending a `USR2` signal: 21 | 22 | ``` 23 | # Trigger bug 24 | kubectl exec \ 25 | $(kubectl get pods -l app=productcatalogservice -o jsonpath='{.items[0].metadata.name}') \ 26 | -c server -- kill -USR1 1 27 | # Remove bug 28 | kubectl exec \ 29 | $(kubectl get pods -l app=productcatalogservice -o jsonpath='{.items[0].metadata.name}') \ 30 | -c server -- kill -USR2 1 31 | ``` 32 | 33 | ## Latency injection 34 | 35 | This service has an `EXTRA_LATENCY` environment variable. This will inject a sleep for the specified [time.Duration](https://golang.org/pkg/time/#ParseDuration) on every call to 36 | to the server. 37 | 38 | For example, use `EXTRA_LATENCY="5.5s"` to sleep for 5.5 seconds on every request. 39 | -------------------------------------------------------------------------------- /microservices-demo/src/productcatalogservice/genproto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # [START gke_productcatalogservice_genproto] 18 | 19 | PATH=$PATH:$GOPATH/bin 20 | protodir=../../pb 21 | 22 | protoc --go_out=plugins=grpc:genproto -I $protodir $protodir/demo.proto 23 | 24 | # [END gke_productcatalogservice_genproto] -------------------------------------------------------------------------------- /microservices-demo/src/productcatalogservice/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/GoogleCloudPlatform/microservices-demo/src/productcatalogservice 2 | 3 | go 1.18 4 | 5 | require ( 6 | cloud.google.com/go/profiler v0.3.0 7 | contrib.go.opencensus.io/exporter/jaeger v0.2.1 8 | contrib.go.opencensus.io/exporter/stackdriver v0.13.12 9 | github.com/golang/protobuf v1.5.2 10 | github.com/google/go-cmp v0.5.8 11 | github.com/sirupsen/logrus v1.8.1 12 | go.opencensus.io v0.23.0 13 | golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b 14 | google.golang.org/grpc v1.48.0 15 | ) 16 | 17 | require ( 18 | cloud.google.com/go v0.100.2 // indirect 19 | cloud.google.com/go/compute v1.6.1 // indirect 20 | cloud.google.com/go/monitoring v1.1.0 // indirect 21 | cloud.google.com/go/trace v1.0.0 // indirect 22 | github.com/aws/aws-sdk-go v1.43.31 // indirect 23 | github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect 24 | github.com/cespare/xxhash/v2 v2.1.1 // indirect 25 | github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect 26 | github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 // indirect 27 | github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect 28 | github.com/envoyproxy/protoc-gen-validate v0.1.0 // indirect 29 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 30 | github.com/google/pprof v0.0.0-20220412212628-83db2b799d1f // indirect 31 | github.com/googleapis/gax-go/v2 v2.4.0 // indirect 32 | github.com/jmespath/go-jmespath v0.4.0 // indirect 33 | github.com/prometheus/prometheus v2.5.0+incompatible // indirect 34 | github.com/uber/jaeger-client-go v2.25.0+incompatible // indirect 35 | golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect 36 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect 37 | golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect 38 | golang.org/x/text v0.3.7 // indirect 39 | google.golang.org/api v0.78.0 // indirect 40 | google.golang.org/appengine v1.6.7 // indirect 41 | google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335 // indirect 42 | google.golang.org/protobuf v1.28.0 // indirect 43 | ) 44 | -------------------------------------------------------------------------------- /microservices-demo/src/productcatalogservice/server_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "context" 19 | "testing" 20 | 21 | pb "github.com/GoogleCloudPlatform/microservices-demo/src/productcatalogservice/genproto" 22 | "github.com/golang/protobuf/proto" 23 | "github.com/google/go-cmp/cmp" 24 | "go.opencensus.io/plugin/ocgrpc" 25 | "google.golang.org/grpc" 26 | "google.golang.org/grpc/codes" 27 | "google.golang.org/grpc/status" 28 | ) 29 | 30 | func TestServer(t *testing.T) { 31 | ctx := context.Background() 32 | addr := run(port) 33 | conn, err := grpc.DialContext(ctx, addr, 34 | grpc.WithInsecure(), 35 | grpc.WithStatsHandler(&ocgrpc.ClientHandler{})) 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | defer conn.Close() 40 | client := pb.NewProductCatalogServiceClient(conn) 41 | res, err := client.ListProducts(ctx, &pb.Empty{}) 42 | if err != nil { 43 | t.Fatal(err) 44 | } 45 | if diff := cmp.Diff(res.Products, parseCatalog(), cmp.Comparer(proto.Equal)); diff != "" { 46 | t.Error(diff) 47 | } 48 | 49 | got, err := client.GetProduct(ctx, &pb.GetProductRequest{Id: "OLJCESPC7Z"}) 50 | if err != nil { 51 | t.Fatal(err) 52 | } 53 | if want := parseCatalog()[0]; !proto.Equal(got, want) { 54 | t.Errorf("got %v, want %v", got, want) 55 | } 56 | _, err = client.GetProduct(ctx, &pb.GetProductRequest{Id: "N/A"}) 57 | if got, want := status.Code(err), codes.NotFound; got != want { 58 | t.Errorf("got %s, want %s", got, want) 59 | } 60 | 61 | sres, err := client.SearchProducts(ctx, &pb.SearchProductsRequest{Query: "sunglasses"}) 62 | if err != nil { 63 | t.Fatal(err) 64 | } 65 | if diff := cmp.Diff(sres.Results, []*pb.Product{parseCatalog()[0]}, cmp.Comparer(proto.Equal)); diff != "" { 66 | t.Error(diff) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /microservices-demo/src/recommendationservice/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /microservices-demo/src/recommendationservice/.python-version: -------------------------------------------------------------------------------- 1 | 3.7 2 | -------------------------------------------------------------------------------- /microservices-demo/src/recommendationservice/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM python:3.7-slim 16 | RUN apt-get update -qqy && \ 17 | apt-get -qqy install wget g++ && \ 18 | rm -rf /var/lib/apt/lists/* 19 | # show python logs as they occur 20 | ENV PYTHONUNBUFFERED=0 21 | 22 | # download the grpc health probe 23 | RUN GRPC_HEALTH_PROBE_VERSION=v0.4.11 && \ 24 | wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ 25 | chmod +x /bin/grpc_health_probe 26 | 27 | # get packages 28 | WORKDIR /recommendationservice 29 | COPY requirements.txt requirements.txt 30 | RUN pip install -r requirements.txt 31 | 32 | # add files into working directory 33 | COPY . . 34 | 35 | # set listen port 36 | ENV PORT "8080" 37 | EXPOSE 8080 38 | 39 | ENTRYPOINT ["python", "/recommendationservice/recommendation_server.py"] 40 | -------------------------------------------------------------------------------- /microservices-demo/src/recommendationservice/Procfile: -------------------------------------------------------------------------------- 1 | web: python /recommendationservice/recommendation_server.py 2 | -------------------------------------------------------------------------------- /microservices-demo/src/recommendationservice/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import sys 18 | import grpc 19 | import demo_pb2 20 | import demo_pb2_grpc 21 | 22 | from opencensus.trace.tracer import Tracer 23 | from opencensus.trace.exporters import stackdriver_exporter 24 | from opencensus.trace.ext.grpc import client_interceptor 25 | 26 | from logger import getJSONLogger 27 | logger = getJSONLogger('recommendationservice-server') 28 | 29 | if __name__ == "__main__": 30 | # get port 31 | if len(sys.argv) > 1: 32 | port = sys.argv[1] 33 | else: 34 | port = "8080" 35 | 36 | try: 37 | exporter = stackdriver_exporter.StackdriverExporter() 38 | tracer = Tracer(exporter=exporter) 39 | tracer_interceptor = client_interceptor.OpenCensusClientInterceptor(tracer, host_port='localhost:'+port) 40 | except: 41 | tracer_interceptor = client_interceptor.OpenCensusClientInterceptor() 42 | 43 | # set up server stub 44 | channel = grpc.insecure_channel('localhost:'+port) 45 | channel = grpc.intercept_channel(channel, tracer_interceptor) 46 | stub = demo_pb2_grpc.RecommendationServiceStub(channel) 47 | # form request 48 | request = demo_pb2.ListRecommendationsRequest(user_id="test", product_ids=["test"]) 49 | # make call to server 50 | response = stub.ListRecommendations(request) 51 | logger.info(response) 52 | -------------------------------------------------------------------------------- /microservices-demo/src/recommendationservice/genproto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # [START gke_recommendationservice_genproto] 18 | 19 | # script to compile python protos 20 | # 21 | # requires gRPC tools: 22 | # pip install -r requirements.txt 23 | 24 | python -m grpc_tools.protoc -I../../pb --python_out=. --grpc_python_out=. ../../pb/demo.proto 25 | 26 | # [END gke_recommendationservice_genproto] -------------------------------------------------------------------------------- /microservices-demo/src/recommendationservice/logger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import logging 18 | import sys 19 | from pythonjsonlogger import jsonlogger 20 | 21 | # TODO(yoshifumi) this class is duplicated since other Python services are 22 | # not sharing the modules for logging. 23 | class CustomJsonFormatter(jsonlogger.JsonFormatter): 24 | def add_fields(self, log_record, record, message_dict): 25 | super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict) 26 | if not log_record.get('timestamp'): 27 | log_record['timestamp'] = record.created 28 | if log_record.get('severity'): 29 | log_record['severity'] = log_record['severity'].upper() 30 | else: 31 | log_record['severity'] = record.levelname 32 | 33 | def getJSONLogger(name): 34 | logger = logging.getLogger(name) 35 | handler = logging.StreamHandler(sys.stdout) 36 | formatter = CustomJsonFormatter('(timestamp) (severity) (name) (message)') 37 | handler.setFormatter(formatter) 38 | logger.addHandler(handler) 39 | logger.setLevel(logging.INFO) 40 | logger.propagate = False 41 | return logger 42 | -------------------------------------------------------------------------------- /microservices-demo/src/recommendationservice/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | testpaths = tests 3 | console_output_style = classic 4 | -------------------------------------------------------------------------------- /microservices-demo/src/recommendationservice/requirements.in: -------------------------------------------------------------------------------- 1 | google-api-core==2.8.2 2 | google-python-cloud-debugger==3.1 3 | google-cloud-profiler==4.0.0 4 | grpcio-health-checking==1.47.0 5 | grpcio==1.47.0 6 | opencensus==0.9.0 7 | opencensus-ext-stackdriver==0.8.0 8 | opencensus-ext-grpc==0.7.2 9 | python-json-logger==2.0.4 10 | requests==2.28.1 11 | rsa==4.8 12 | pyyaml==6.0 13 | protobuf==3.20.1 # transitive dependency, move when google-api is bumped safely 14 | pytest==7.1.3 15 | -------------------------------------------------------------------------------- /microservices-demo/src/recommendationservice/tests/test_sample.py: -------------------------------------------------------------------------------- 1 | def func(x): 2 | return x + 1 3 | 4 | 5 | def test_answer(): 6 | assert func(3) == 4 7 | -------------------------------------------------------------------------------- /microservices-demo/src/shippingservice/.dockerignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | -------------------------------------------------------------------------------- /microservices-demo/src/shippingservice/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM golang:1.18.4-alpine as builder 16 | RUN apk add --no-cache ca-certificates git 17 | RUN apk add build-base 18 | WORKDIR /src 19 | 20 | # restore dependencies 21 | COPY go.mod go.sum ./ 22 | RUN go mod download 23 | COPY . . 24 | 25 | # Skaffold passes in debug-oriented compiler flags 26 | ARG SKAFFOLD_GO_GCFLAGS 27 | RUN go build -gcflags="${SKAFFOLD_GO_GCFLAGS}" -o /go/bin/shippingservice . 28 | 29 | FROM alpine as release 30 | RUN apk add --no-cache ca-certificates 31 | RUN GRPC_HEALTH_PROBE_VERSION=v0.4.11 && \ 32 | wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ 33 | chmod +x /bin/grpc_health_probe 34 | WORKDIR /src 35 | COPY --from=builder /go/bin/shippingservice /src/shippingservice 36 | ENV APP_PORT=50051 37 | 38 | # Definition of this variable is used by 'skaffold debug' to identify a golang binary. 39 | # Default behavior - a failure prints a stack trace for the current goroutine. 40 | # See https://golang.org/pkg/runtime/ 41 | ENV GOTRACEBACK=single 42 | 43 | EXPOSE 50051 44 | ENTRYPOINT ["/src/shippingservice"] 45 | -------------------------------------------------------------------------------- /microservices-demo/src/shippingservice/README.md: -------------------------------------------------------------------------------- 1 | # Shipping Service 2 | 3 | The Shipping service provides price quote, tracking IDs, and the impression of order fulfillment & shipping processes. 4 | 5 | ## Local 6 | 7 | Run the following command to restore dependencies to `vendor/` directory: 8 | 9 | dep ensure --vendor-only 10 | 11 | ## Build 12 | 13 | From `src/shippingservice`, run: 14 | 15 | ``` 16 | docker build ./ 17 | ``` 18 | 19 | ## Test 20 | 21 | ``` 22 | go test . 23 | ``` 24 | -------------------------------------------------------------------------------- /microservices-demo/src/shippingservice/genproto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # [START gke_shippingservice_genproto] 18 | 19 | PATH=$PATH:$GOPATH/bin 20 | protodir=../../pb 21 | 22 | protoc --go_out=plugins=grpc:genproto -I $protodir $protodir/demo.proto 23 | 24 | # [END gke_shippingservice_genproto] -------------------------------------------------------------------------------- /microservices-demo/src/shippingservice/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/GoogleCloudPlatform/microservices-demo/src/shippingservice 2 | 3 | go 1.18 4 | 5 | require ( 6 | cloud.google.com/go/profiler v0.3.0 7 | contrib.go.opencensus.io/exporter/jaeger v0.2.1 8 | contrib.go.opencensus.io/exporter/stackdriver v0.13.12 9 | github.com/golang/protobuf v1.5.2 10 | github.com/sirupsen/logrus v1.8.1 11 | go.opencensus.io v0.23.0 12 | golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b 13 | google.golang.org/grpc v1.48.0 14 | ) 15 | 16 | require ( 17 | cloud.google.com/go v0.100.2 // indirect 18 | cloud.google.com/go/compute v1.6.1 // indirect 19 | cloud.google.com/go/monitoring v1.1.0 // indirect 20 | cloud.google.com/go/trace v1.0.0 // indirect 21 | github.com/aws/aws-sdk-go v1.43.31 // indirect 22 | github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect 23 | github.com/cespare/xxhash/v2 v2.1.1 // indirect 24 | github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect 25 | github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 // indirect 26 | github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect 27 | github.com/envoyproxy/protoc-gen-validate v0.1.0 // indirect 28 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 29 | github.com/google/go-cmp v0.5.8 // indirect 30 | github.com/google/pprof v0.0.0-20220412212628-83db2b799d1f // indirect 31 | github.com/googleapis/gax-go/v2 v2.4.0 // indirect 32 | github.com/jmespath/go-jmespath v0.4.0 // indirect 33 | github.com/prometheus/prometheus v2.5.0+incompatible // indirect 34 | github.com/uber/jaeger-client-go v2.25.0+incompatible // indirect 35 | golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect 36 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect 37 | golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect 38 | golang.org/x/text v0.3.7 // indirect 39 | google.golang.org/api v0.78.0 // indirect 40 | google.golang.org/appengine v1.6.7 // indirect 41 | google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335 // indirect 42 | google.golang.org/protobuf v1.28.0 // indirect 43 | ) 44 | -------------------------------------------------------------------------------- /microservices-demo/src/shippingservice/quote.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "fmt" 19 | "math" 20 | ) 21 | 22 | // Quote represents a currency value. 23 | type Quote struct { 24 | Dollars uint32 25 | Cents uint32 26 | } 27 | 28 | // String representation of the Quote. 29 | func (q Quote) String() string { 30 | return fmt.Sprintf("$%d.%d", q.Dollars, q.Cents) 31 | } 32 | 33 | // CreateQuoteFromCount takes a number of items and returns a Price struct. 34 | func CreateQuoteFromCount(count int) Quote { 35 | return CreateQuoteFromFloat(8.99) 36 | } 37 | 38 | // CreateQuoteFromFloat takes a price represented as a float and creates a Price struct. 39 | func CreateQuoteFromFloat(value float64) Quote { 40 | units, fraction := math.Modf(value) 41 | return Quote{ 42 | uint32(units), 43 | uint32(math.Trunc(fraction * 100)), 44 | } 45 | } -------------------------------------------------------------------------------- /microservices-demo/src/shippingservice/shippingservice_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "testing" 19 | 20 | "golang.org/x/net/context" 21 | 22 | pb "github.com/GoogleCloudPlatform/microservices-demo/src/shippingservice/genproto" 23 | ) 24 | 25 | // TestGetQuote is a basic check on the GetQuote RPC service. 26 | func TestGetQuote(t *testing.T) { 27 | s := server{} 28 | 29 | // A basic test case to test logic and protobuf interactions. 30 | req := &pb.GetQuoteRequest{ 31 | Address: &pb.Address{ 32 | StreetAddress: "Muffin Man", 33 | City: "London", 34 | State: "", 35 | Country: "England", 36 | }, 37 | Items: []*pb.CartItem{ 38 | { 39 | ProductId: "23", 40 | Quantity: 1, 41 | }, 42 | { 43 | ProductId: "46", 44 | Quantity: 3, 45 | }, 46 | }, 47 | } 48 | 49 | res, err := s.GetQuote(context.Background(), req) 50 | if err != nil { 51 | t.Errorf("TestGetQuote (%v) failed", err) 52 | } 53 | if res.CostUsd.GetUnits() != 8 || res.CostUsd.GetNanos() != 990000000 { 54 | t.Errorf("TestGetQuote: Quote value '%d.%d' does not match expected '%s'", res.CostUsd.GetUnits(), res.CostUsd.GetNanos(), "11.220000000") 55 | } 56 | } 57 | 58 | // TestShipOrder is a basic check on the ShipOrder RPC service. 59 | func TestShipOrder(t *testing.T) { 60 | s := server{} 61 | 62 | // A basic test case to test logic and protobuf interactions. 63 | req := &pb.ShipOrderRequest{ 64 | Address: &pb.Address{ 65 | StreetAddress: "Muffin Man", 66 | City: "London", 67 | State: "", 68 | Country: "England", 69 | }, 70 | Items: []*pb.CartItem{ 71 | { 72 | ProductId: "23", 73 | Quantity: 1, 74 | }, 75 | { 76 | ProductId: "46", 77 | Quantity: 3, 78 | }, 79 | }, 80 | } 81 | 82 | res, err := s.ShipOrder(context.Background(), req) 83 | if err != nil { 84 | t.Errorf("TestShipOrder (%v) failed", err) 85 | } 86 | // @todo improve quality of this test to check for a pattern such as '[A-Z]{2}-\d+-\d+'. 87 | if len(res.TrackingId) != 18 { 88 | t.Errorf("TestShipOrder: Tracking ID is malformed - has %d characters, %d expected", len(res.TrackingId), 18) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /microservices-demo/src/shippingservice/tracker.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "fmt" 19 | "math/rand" 20 | "time" 21 | ) 22 | 23 | // seeded determines if the random number generator is ready. 24 | var seeded bool = false 25 | 26 | // CreateTrackingId generates a tracking ID. 27 | func CreateTrackingId(salt string) string { 28 | if !seeded { 29 | rand.Seed(time.Now().UnixNano()) 30 | seeded = true 31 | } 32 | 33 | return fmt.Sprintf("%c%c-%d%s-%d%s", 34 | getRandomLetterCode(), 35 | getRandomLetterCode(), 36 | len(salt), 37 | getRandomNumber(3), 38 | len(salt)/2, 39 | getRandomNumber(7), 40 | ) 41 | } 42 | 43 | // getRandomLetterCode generates a code point value for a capital letter. 44 | func getRandomLetterCode() uint32 { 45 | return 65 + uint32(rand.Intn(25)) 46 | } 47 | 48 | // getRandomNumber generates a string representation of a number with the requested number of digits. 49 | func getRandomNumber(digits int) string { 50 | str := "" 51 | for i := 0; i < digits; i++ { 52 | str = fmt.Sprintf("%s%d", str, rand.Intn(10)) 53 | } 54 | 55 | return str 56 | } 57 | -------------------------------------------------------------------------------- /microservices-demo/tilt-resources/dev/tilt_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "allowed_contexts": [ 3 | "do-nyc1-microservices-demo-dev" 4 | ], 5 | "default_registry": "registry.digitalocean.com/microservices-demo", 6 | "environment": "dev", 7 | "microservices": [ 8 | "cartservice", 9 | "checkoutservice", 10 | "currencyservice", 11 | "emailservice", 12 | "frontend", 13 | "paymentservice", 14 | "productcatalogservice", 15 | "recommendationservice", 16 | "redis", 17 | "shippingservice" 18 | ], 19 | "namespace": "microservices-demo-dev", 20 | "port_forwards": [ 21 | "frontend:9090" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /microservices-demo/tilt-resources/local/tilt_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "allowed_contexts": [ 3 | "docker-desktop" 4 | ], 5 | "default_registry": "", 6 | "environment": "local", 7 | "microservices": [ 8 | "cartservice", 9 | "checkoutservice", 10 | "currencyservice", 11 | "emailservice", 12 | "frontend", 13 | "paymentservice", 14 | "productcatalogservice", 15 | "recommendationservice", 16 | "redis", 17 | "shippingservice" 18 | ], 19 | "namespace": "microservices-demo-local", 20 | "port_forwards": [ 21 | "frontend:9090" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /podinfo-example/assets/images/podinfo-welcome-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitalocean/kubernetes-sample-apps/6d8ffb91dc2644c277b82af403c9f9bb0f1d1353/podinfo-example/assets/images/podinfo-welcome-page.png -------------------------------------------------------------------------------- /podinfo-example/kustomize/kustomization.yaml: -------------------------------------------------------------------------------- 1 | ## Podinfo Sample Application Kustomization 2 | 3 | apiVersion: kustomize.config.k8s.io/v1beta1 4 | kind: Kustomization 5 | 6 | # Making sure all resources used in this tutorial are created in a dedicated namespace 7 | # Also specific annotations are added for later identification 8 | namespace: podinfo 9 | commonAnnotations: 10 | provider: kubernetes-sample-apps 11 | 12 | # Podinfo resources (namespace, services, deployments, etc) 13 | resources: 14 | - resources/namespace.yaml 15 | - github.com/stefanprodan/podinfo/kustomize 16 | -------------------------------------------------------------------------------- /podinfo-example/kustomize/resources/namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: podinfo 5 | --------------------------------------------------------------------------------