{"id":23536197,"url":"https://github.com/hamdiz0/online-boutique-app","last_synced_at":"2026-02-13T06:41:40.716Z","repository":{"id":269622700,"uuid":"896658161","full_name":"hamdiz0/online-boutique-app","owner":"hamdiz0","description":"A containerized online boutique app with 11 microservices built ,pushed and deployed with a CI/CD pipline using Docker ,Jenkins ,Nexus , Argocd and an on premesis Kubernetes cluster setup with kubeadm using vagrant","archived":false,"fork":false,"pushed_at":"2025-01-01T00:55:32.000Z","size":22634,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-12T09:06:18.948Z","etag":null,"topics":["argo","cicd","devops","docker","jenkins","kubeadm-cluster","kubernetes","script","sonatype-nexus","vagrant","yaml"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hamdiz0.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-12-01T00:21:06.000Z","updated_at":"2025-02-27T10:19:21.000Z","dependencies_parsed_at":"2025-01-01T01:24:26.231Z","dependency_job_id":"83072d5b-52c0-4ce5-be20-47e666faca46","html_url":"https://github.com/hamdiz0/online-boutique-app","commit_stats":null,"previous_names":["hamdiz0/market-app","hamdiz0/online-boutique-app"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hamdiz0/online-boutique-app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamdiz0%2Fonline-boutique-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamdiz0%2Fonline-boutique-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamdiz0%2Fonline-boutique-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamdiz0%2Fonline-boutique-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hamdiz0","download_url":"https://codeload.github.com/hamdiz0/online-boutique-app/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamdiz0%2Fonline-boutique-app/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29398144,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-13T06:24:03.484Z","status":"ssl_error","status_checked_at":"2026-02-13T06:23:12.830Z","response_time":78,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["argo","cicd","devops","docker","jenkins","kubeadm-cluster","kubernetes","script","sonatype-nexus","vagrant","yaml"],"created_at":"2024-12-26T02:17:27.600Z","updated_at":"2026-02-13T06:41:40.676Z","avatar_url":"https://github.com/hamdiz0.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Online-Boutique-app\n\nBased on \u003ca href=\"https://github.com/GoogleCloudPlatform/microservices-demo.git\"\u003emicroservices-demo\u003c/a\u003e \n\n- [Prerequisites](#prerequisites-)\n- [Architecture](#architecture-)\n- [Infrastructure and Tools](#infrastructure-and-tools-)\n    - [Setting up Jenkins](#setting-up-jenkins-)\n    - [Setting up Nexuss](#setting-up-nexus-)\n- [YAML files](#yaml-files-)\n- [CI/CD Pipeline](#cicd-pipeline-)\n  - [CI Pipeline](#ci-pipeline-)\n    - [Building \u0026 Pushing docker images](#building--pushing-docker-images-)\n    - [Updating the Version](#updating-the-version-)\n    - [Pushing the version change](#pushing-the-version-change-)\n  - [CD Pipeline](#cd-pipeline-gitops-with-argocd-)\n    - [Setting up Argocd](#setting-up-argocd-on-the-k8s-cluster-)\n    - [Configuring Argocd](#configuring-argocd-)\n- [Results](#results-)\n\nA containerized online boutique app with 11 microservices built ,pushed and deployed with a CI/CD pipline using Docker ,Jenkins ,Nexus , Argocd and an on premesis Kubernetes cluster setup with kubeadm using vagrant \n\n## Prerequisites :\n\n* Docker\n* A kubernetes cluster\n* Jenkins \n* Nexus\n* Argocd\n\n## Architecture :\n\n\u003cimg src=\"./img/arch.PNG\" style=\"width:100%\"\u003e\n\n| Service                       |               | Description                                                       |\n| ----------------------------- | ------------- | ----------------------------------------------------------------- |\n| frontend                      | Go            | serve the website                                                 |\n| cartservice                   | C#            | stores selected items in the shopping cart                        |\n| productcatalogservice         | Go            | list ,search and select products                                  |\n| currencyservice               | Node.js       | converts currency                                                 |\n| paymentservice                | Node.js       | charges the given credit card (mock)                              |      \n| shippingservice               | Go            | extimate shipping cost (mock)                                     |\n| emailservice                  | Python        | sends emails about the transactions (mock)                        |                                                         \n| checkoutservice               | Go            | manage the cart ,order ,shipping ,payment and email notifications |                           \n| recommendationservice         | Python        | recommends other products                                         |                            \n| adservice                     | Java          | provides text ads                                                 |\n\n## Infrastructure and Tools :\n\n\u003cimg src=\"./img/inf.PNG\" style=\"width:100%\"\u003e\n\n* A Kubernetes cluster setup with kubeadm using vagrant\n    - here is guide on how to setup a k8s cluster with vagrant and kubeadm \u003ca href=\"https://github.com/vancanhuit/vagrant-k8s\"\u003evagrant-k8s\u003c/a\u003e\n* A Jenkins container, setup on a VM (4Cpu,6Ram) runnig on port 8080\n* Nexus repository on the same VM running on port 8081\n* Argocd installed on the k8s cluster and exposed on port 32000\n* I recommend using the same network CIDR if youre using this infrastructure locally\n\n### Setting up Jenkins :\n\n* follow this guide to set up jenkins as a container \u003ca href=\"https://github.com/hamdiz0/LearningDevOps/blob/main/jenkins/README.md#doker-in-jenkins\"\u003eDocker in Jenkins\u003c/a\u003e\n\n### Setting up Nexus :\n\n* For the docker registry you can use Docker Hub or others, in this case i used Sonatype Nexus\n* install \u0026 start Nexus :\n    ```\n    sudo apt install openjdk-17-jdk openjdk-17-jre\n    wget https://sonatype-download.global.ssl.fastly.net/repository/downloads-prod-group/3/nexus-3.74.0-05-unix.tar.gz\n    tar -zxvf nexus-3.74.0-05-unix.tar.gz\n    nexus-version/bin/nexus start\n    ```\n* setup a docker hosted registry (repository =\u003e create repository =\u003e docker hosted ) :\n\n    \u003cimg src=\"./img/regis.PNG\" style=\"width:100%\"\u003e\n\n* create a role that grants access to the created registry (admin setting =\u003e roles =\u003e create role) :\n\n    \u003cimg src=\"./img/role.PNG\" style=\"width:100%\"\u003e\n\n* create jenkins \u0026 kubernetes users in Nexus (you can create one for both) :\n    - make sure to add the created docker hosted role to these users \n    \u003cimg src=\"./img/adduser.PNG\" style=\"width:100%\"\u003e\n\n* allow jenkins and the k8s cluster to pull \u0026 push images :\n    * for docker runtime :\n        - edit the daemon.json file :\n            ```\n            sudo nano /etc/docker/daemon.json\n            ```\n            * configuration example :\n                ```\n                {\n                insecure-registries\": [\"192.168.1.16:8082\"]\n                }\n                ```\n            * restart docker :\n                ```\n                sudo systemctl restart docker\n                ```\n    * for containerd runtime :\n        - create \u0026 edit the hosts.toml file :\n            ```\n            sudo mkdir -p /etc/containerd/certs.d/192.168.1.16:8082/\n            sudo nano /etc/containerd/certs.d/192.168.1.16:8082/hosts.toml\n            ```\n            * configuration example :\n                ```\n                server = \"http://192.168.1.16:8082\"\n                [host.\"http://192.168.1.16:8082\"]\n                capabilities = [\"pull\", \"resolve\"]\n                ```\n        - modify the config file :\n            ```\n            sudo nano /etc/containerd/config.toml\n            ```\n            * add this :\n                ```\n                [plugins.\"io.containerd.grpc.v1.cri\".registry]\n                config_path = \"/etc/containerd/certs.d\"\n                ```\n        - restart containerd:\n            ```\n            sudo systemctl restart containerd\n            ```\n\n## YAML files :\n\n* set up a deployment with its corresponding service for each microservices\n* utilized a script to manually deploy and test the app on the k8s cluster\n    - view the `run.sh` script \u003ca href=\"./k8s-manifests/run.sh\"\u003ehere\u003c/a\u003e\n    - view the YAML files \u003ca href=\"./k8s-manifests\"\u003ehere\u003c/a\u003e\n* make sure to add secret in the k8s cluster to allow acces to the Nexus repo using the user created previously\n    ```\n    kubectl create secret docker-registry nexus-registry-secret --docker-server=192.168.1.16:8082 --docker-username=kubernetes --docker-password=kubernetes\n    ```\n* also make sure to add the imagePullSecrets and specify the secrect name in each YAML file\n    ```\n    template:\n      metadata:\n        labels:\n          app: frontend\n      spec:\n        imagePullSecrets:\n        - name: nexus-registry-secret\n        containers:\n          - name: frontend\n            image: 192.168.1.16:8082/frontend:1.0.4\n    ```\n\n## CI/CD Pipeline :\n\n\u003cimg src=\"./img/cicd.PNG\" style=\"width:100%\"\u003e\n\n## CI Pipeline :\n\n* Utilized webhook triggers to launch the pipline automaticly\n* I recommnad using Ngrok if youre planning on using webhooks on a local setup \n    - visit Ngrok \u003ca href=\"https://ngrok.com/\"\u003ehere\u003c/a\u003e\n    - more details about webhook triggers \u003ca href=\"https://github.com/hamdiz0/LearningDevOps/blob/main/jenkins/README.md#job-triggers\"\u003ehere\u003c/a\u003e\n* I also recommend using a multibranch pipline for its usefull plugins like the `Ignore Commiter Strategy` and `Multibranch Scan Webhook Trigger`\n\n\u003cimg src=\"./img/ci.PNG\" style=\"width:100%\"\u003e\n\n### Building \u0026 Pushing docker images :\n\n* utilzed a function to build multiple images by passing a list of (ImageName with corresponding Docker File Location) pairs\n    - view the funtcion \u003ca href=\"./script.groovy\"\u003ehere\u003c/a\u003e\n    - example :\n        ```\n        def ImageName_DockerFileLocation=[['frontend','services/frontend'],['adservice','services/adservice']]\n        gs.build(\n            '192.168.1.16:8082',                    // Nexus repo url\n            env.VERSION,                            // Version\n            'nexus-jenkins',                        // Credentail Id for docker repo from jenkins \n            ImageName_DockerFileLocation            // List of pairs (Image Name along with Docker File Location)\n        )\n        ```\n* another function pushes the images the docker registry by passing in a list of the built Image names \n    - view the funtcion \u003ca href=\"./script.groovy\"\u003ehere\u003c/a\u003e\n    - example :\n        ```\n        ImageNames=['frontend','adservice']\n            gs.push(\n            '192.168.1.16:8082',                    // Nexus url\n            env.VERSION,                            // Version\n            'nexus-jenkins',                        // Credentail Id for docker repo from jenkins \n            ImageNames                              // List of Image Names\n            )\n        ```\n\n### Updating the Version :\n\n* utilized the `$BUILD_NUMBER` built in jenkins pipline variable in the versioning of the docker images\n* implemeted a script that changes the YAML file image version after each commit\n    - view the script \u003ca href=\"./script.groovy\"\u003ehere\u003c/a\u003e\n        ```\n        version=1.2.3\n        file=\"./deployment.yml\"\n        sed -i \"s|image: 192.168.1.16/\\([^:]*\\):.*|image: 192.168.1.16/\\1:$version|\" $file\n        ```\n        * search for this exact pattern \"image: 192.168.1.16/`\u003cimageName\u003e`:`\u003cversion\u003e`\"\n        * `\\([^:]*\\)` : capture the `\u003cimageName\u003e`\n        * `.*` : select anything after \":\"\n        * `/1` : keep the same `\u003cimageName\u003e`=\u003e`\\([^:]*\\)`\n        * change the version to `$version`\n        * `-i` : write directly in the file\n\n### Pushing the version change :\n\n* set up jenkins to update the git repository with new YAML files version\n* set up a git user.name and user.eamil for jenkins :\n    ```\n    docker exec -it jenkins bash\n    git config --global user.name \"jenkins\"\n    git config user.email \"jenkins@jenkins.com\"\n    ```\n* ustilized a function that adds and push changes to a git repository \n    - view the function \u003ca href=\"./script.groovy\"\u003ehere\u003c/a\u003e\n* the function uses a git access token wish must be configured and added to jenkins as a `Username and Password` credentail\n    - set up an access token in git hub :\n    \u003cimg src=\"./img/token.PNG\" style=\"width:100%\"\u003e\n* make sure to add the `Ignore Commiter Strategy` plugin and ignore jenkins pushes to avoid infinite build loops :\n    \u003cimg src=\"./img/avoid.PNG\" style=\"width:100%\"\u003e\n\n## CD Pipeline (GitOps with Argocd) :\n\n\u003cimg src=\"./img/cd.PNG\" style=\"width:100%\"\u003e\n\n### Setting up Argocd on the k8s cluster :\n    \n* install Argocd :\n    ```\n    kubectl create namespace argocd\n    kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml\n    kubectl delete pod -n argocd --all # hard reset of the pods\n    kubectl get pods -n argocd\n    ```\n* expose the ui on port 32000 :\n    ```\n    kubectl patch svc argocd-server -n argocd -p '{\"spec\": {\"type\": \"NodePort\", \"ports\": [{\"port\": 443, \"targetPort\": 8080, \"nodePort\": 32000}]}}'\n    ```\n* retrieve the admin password to login in th ui :\n    ```\n    kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath=\"{.data.password}\" | base64 -d\n    ```\n\n### Configuring Argocd :\n\n* create a new app and add the :\n    - git repository url\n    - branch \n    - YAML manifests location in the git rpository\n    - destination cluster (`https://kubernetes.default.svc` for the current local cluster)\n    - namespace \n\n\u003cimg src=\"./img/argo1.PNG\" style=\"width:100%\"\u003e\n\n* make sure the app is healthy and synched :\n\n\u003cimg src=\"./img/argo3.PNG\" style=\"width:100%\"\u003e\n\n## Results :\n\n* Jenkins pipline :\n\n\u003cimg src=\"./img/res0.PNG\" style=\"width:100%\"\u003e\n\n* Nexus repo :\n\n\u003cimg src=\"./img/res3.PNG\" style=\"width:100%\"\u003e\n\n* Argocd's deployment :\n\n\u003cimg src=\"./img/argo2.PNG\" style=\"width:100%\"\u003e\n\n* kubectl get pods,svc,deploy :\n\n\u003cimg src=\"./img/res1.PNG\" style=\"width:100%\"\u003e\n\n* market-app :\n\n\u003cimg src=\"./img/app1.PNG\" style=\"width:100%\"\u003e\n\n\u003cimg src=\"./img/app2.PNG\" style=\"width:50%\"\u003e\u003cimg src=\"./img/app3.PNG\" style=\"width:50%\"\u003e\n\n\u003cimg src=\"./img/app4.PNG\" style=\"width:100%\"\u003e\n\n## Checkout my \u003ca href=\"https://github.com/hamdiz0/LearningDevOps\"\u003eLearningDevops\u003c/a\u003e repo for more details about these tools and devops in general do not hesitate to contribute\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhamdiz0%2Fonline-boutique-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhamdiz0%2Fonline-boutique-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhamdiz0%2Fonline-boutique-app/lists"}