[{"data":1,"prerenderedAt":438},["ShallowReactive",2],{"nav-stories":3,"footer-stories":61,"blog-building-swarm-cluster-openstack":74},[4,16,25,34,43,52],{"id":5,"color":6,"extension":7,"image":8,"label":9,"link":10,"meta":11,"order":12,"stem":13,"text":14,"__hash__":15},"stories\u002Fstories\u002F01-data-center.yml",null,"yml","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1558494949-ef010cbdcc31?w=1080","DATA_CENTER","https:\u002F\u002Fx.com\u002Fabbeytetteh_",{},1,"stories\u002F01-data-center","Racking new servers. 40gbit backbone online.","0QUZQbaANhdO8WemZxkDdO7vbVopfnynHtH9FxBZb_w",{"id":17,"color":6,"extension":7,"image":18,"label":19,"link":6,"meta":20,"order":21,"stem":22,"text":23,"__hash__":24},"stories\u002Fstories\u002F02-thoughts.yml","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1498050108023-c5249f4df085?w=1080","THOUGHTS",{},2,"stories\u002F02-thoughts","Late night bug hunting. Found the memory leak.","Gd1am954aasY6HRHD7hCtOuessXb6zYZ8iizS501ICg",{"id":26,"color":27,"extension":7,"image":6,"label":28,"link":6,"meta":29,"order":30,"stem":31,"text":32,"__hash__":33},"stories\u002Fstories\u002F03-coding.yml","#3b82f6","CODING",{},3,"stories\u002F03-coding","Just thinking about how much easier life is with Swarm.","vLAyiGUPtlXB2SHa5KM_U2AaK4QkG3Og85UEUE7qzgM",{"id":35,"color":6,"extension":7,"image":36,"label":37,"link":6,"meta":38,"order":39,"stem":40,"text":41,"__hash__":42},"stories\u002Fstories\u002F04-update.yml","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1591799264318-7e6ef8ddb7ea?w=1080","UPDATE",{},4,"stories\u002F04-update","New cluster nodes arrived. Prepping for installation.","kyT60N5C6Re_jMonZbgNy0PbQhzXmUWxDbD0D_v43ts",{"id":44,"color":45,"extension":7,"image":6,"label":46,"link":6,"meta":47,"order":48,"stem":49,"text":50,"__hash__":51},"stories\u002Fstories\u002F05-setup.yml","#86868b","SETUP",{},5,"stories\u002F05-setup","Optimizing the telemetry pipeline for 1M req\u002Fs.","cPOBkzoyXsCmPgRO2d80Hj3vm4MP-6nAejtlQ5iuSzw",{"id":53,"color":6,"extension":7,"image":54,"label":55,"link":6,"meta":56,"order":57,"stem":58,"text":59,"__hash__":60},"stories\u002Fstories\u002F06-travel.yml","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1560969184-10fe8719e047?w=1080","TRAVEL",{},6,"stories\u002F06-travel","Travel log — system architecture workshop in Berlin.","jnOxerdF6usAIHdR35Z-opx0LJAy9kZluXnZhtz62Z0",[62,64,66,68,70,72],{"id":5,"color":6,"extension":7,"image":8,"label":9,"link":10,"meta":63,"order":12,"stem":13,"text":14,"__hash__":15},{},{"id":17,"color":6,"extension":7,"image":18,"label":19,"link":6,"meta":65,"order":21,"stem":22,"text":23,"__hash__":24},{},{"id":26,"color":27,"extension":7,"image":6,"label":28,"link":6,"meta":67,"order":30,"stem":31,"text":32,"__hash__":33},{},{"id":35,"color":6,"extension":7,"image":36,"label":37,"link":6,"meta":69,"order":39,"stem":40,"text":41,"__hash__":42},{},{"id":44,"color":45,"extension":7,"image":6,"label":46,"link":6,"meta":71,"order":48,"stem":49,"text":50,"__hash__":51},{},{"id":53,"color":6,"extension":7,"image":54,"label":55,"link":6,"meta":73,"order":57,"stem":58,"text":59,"__hash__":60},{},{"id":75,"title":76,"body":77,"date":423,"description":424,"extension":425,"meta":426,"navigation":143,"path":427,"readTime":428,"seo":429,"stem":430,"tags":431,"thumbnail":436,"__hash__":437},"blog\u002Fblog\u002Fbuilding-swarm-cluster-openstack.md","Building a Highly Available Swarm Cluster on OpenStack",{"type":78,"value":79,"toc":417},"minimark",[80,84,89,92,95,99,107,340,343,347,354,399,406,410,413],[81,82,83],"p",{},"Deploying a robust, fault-tolerant cluster isn't just about spinning up instances; it's about engineering resilience at every layer. In this log, I'm documenting the architecture and configuration of a production-grade Docker Swarm cluster running on OpenStack.",[85,86,88],"h2",{"id":87},"the-architecture","The Architecture",[81,90,91],{},"Our foundation requires at least three manager nodes to maintain quorum. Losing a single manager should not degrade the cluster state. Worker nodes scale horizontally across different availability zones to prevent a single point of failure.",[81,93,94],{},"The manager tier handles cluster state, scheduling, and service reconciliation. Workers are provisioned in groups per zone, so a complete AZ outage only removes a fraction of total capacity.",[85,96,98],{"id":97},"network-configuration","Network Configuration",[81,100,101,102,106],{},"Proper overlay networking is critical. We utilize Traefik as the ingress controller, routing traffic efficiently to the appropriate services. The configuration is declared in a ",[103,104,105],"code",{},"docker-compose.yml"," deployed as a stack.",[108,109,114],"pre",{"className":110,"code":111,"language":112,"meta":113,"style":113},"language-yaml shiki shiki-themes vitesse-light","version: \"3.8\"\n\nservices:\n  traefik:\n    image: traefik:v2.9\n    command:\n      - \"--api.insecure=true\"\n      - \"--providers.docker=true\"\n      - \"--providers.docker.swarmMode=true\"\n      - \"--entrypoints.web.address=:80\"\n    ports:\n      - \"80:80\"\n      - \"8080:8080\"\n    networks:\n      - proxy\n    deploy:\n      placement:\n        constraints: [node.role == manager]\n\nnetworks:\n  proxy:\n    external: true\n","yaml","",[103,115,116,139,145,153,160,170,177,190,202,214,226,234,246,258,266,274,282,290,307,312,320,328],{"__ignoreMap":113},[117,118,120,124,128,132,136],"span",{"class":119,"line":12},"line",[117,121,123],{"class":122},"su6XF","version",[117,125,127],{"class":126},"sYZai",":",[117,129,131],{"class":130},"sSP4y"," \"",[117,133,135],{"class":134},"spphp","3.8",[117,137,138],{"class":130},"\"\n",[117,140,141],{"class":119,"line":21},[117,142,144],{"emptyLinePlaceholder":143},true,"\n",[117,146,147,150],{"class":119,"line":30},[117,148,149],{"class":122},"services",[117,151,152],{"class":126},":\n",[117,154,155,158],{"class":119,"line":39},[117,156,157],{"class":122},"  traefik",[117,159,152],{"class":126},[117,161,162,165,167],{"class":119,"line":48},[117,163,164],{"class":122},"    image",[117,166,127],{"class":126},[117,168,169],{"class":134}," traefik:v2.9\n",[117,171,172,175],{"class":119,"line":57},[117,173,174],{"class":122},"    command",[117,176,152],{"class":126},[117,178,180,183,185,188],{"class":119,"line":179},7,[117,181,182],{"class":126},"      -",[117,184,131],{"class":130},[117,186,187],{"class":134},"--api.insecure=true",[117,189,138],{"class":130},[117,191,193,195,197,200],{"class":119,"line":192},8,[117,194,182],{"class":126},[117,196,131],{"class":130},[117,198,199],{"class":134},"--providers.docker=true",[117,201,138],{"class":130},[117,203,205,207,209,212],{"class":119,"line":204},9,[117,206,182],{"class":126},[117,208,131],{"class":130},[117,210,211],{"class":134},"--providers.docker.swarmMode=true",[117,213,138],{"class":130},[117,215,217,219,221,224],{"class":119,"line":216},10,[117,218,182],{"class":126},[117,220,131],{"class":130},[117,222,223],{"class":134},"--entrypoints.web.address=:80",[117,225,138],{"class":130},[117,227,229,232],{"class":119,"line":228},11,[117,230,231],{"class":122},"    ports",[117,233,152],{"class":126},[117,235,237,239,241,244],{"class":119,"line":236},12,[117,238,182],{"class":126},[117,240,131],{"class":130},[117,242,243],{"class":134},"80:80",[117,245,138],{"class":130},[117,247,249,251,253,256],{"class":119,"line":248},13,[117,250,182],{"class":126},[117,252,131],{"class":130},[117,254,255],{"class":134},"8080:8080",[117,257,138],{"class":130},[117,259,261,264],{"class":119,"line":260},14,[117,262,263],{"class":122},"    networks",[117,265,152],{"class":126},[117,267,269,271],{"class":119,"line":268},15,[117,270,182],{"class":126},[117,272,273],{"class":134}," proxy\n",[117,275,277,280],{"class":119,"line":276},16,[117,278,279],{"class":122},"    deploy",[117,281,152],{"class":126},[117,283,285,288],{"class":119,"line":284},17,[117,286,287],{"class":122},"      placement",[117,289,152],{"class":126},[117,291,293,296,298,301,304],{"class":119,"line":292},18,[117,294,295],{"class":122},"        constraints",[117,297,127],{"class":126},[117,299,300],{"class":126}," [",[117,302,303],{"class":134},"node.role == manager",[117,305,306],{"class":126},"]\n",[117,308,310],{"class":119,"line":309},19,[117,311,144],{"emptyLinePlaceholder":143},[117,313,315,318],{"class":119,"line":314},20,[117,316,317],{"class":122},"networks",[117,319,152],{"class":126},[117,321,323,326],{"class":119,"line":322},21,[117,324,325],{"class":122},"  proxy",[117,327,152],{"class":126},[117,329,331,334,336],{"class":119,"line":330},22,[117,332,333],{"class":122},"    external",[117,335,127],{"class":126},[117,337,339],{"class":338},"sbBg2"," true\n",[81,341,342],{},"The overlay network ensures containers on separate physical hosts can communicate as if they are on the same LAN, while Traefik's Swarm mode provider dynamically discovers services as they are deployed.",[85,344,346],{"id":345},"automated-scaling","Automated Scaling",[81,348,349,350,353],{},"Using ",[103,351,352],{},"swarmctl"," alongside custom Prometheus metrics allows us to dynamically provision worker nodes when CPU load exceeds our baseline threshold.",[108,355,359],{"className":356,"code":357,"language":358,"meta":113,"style":113},"language-bash shiki shiki-themes vitesse-light","$ swarmctl cluster update \\\n    --autoscale-cpu-threshold=75 \\\n    --autoscale-max-nodes=10 \\\n    --cluster-name=prod-swarm-alpha\n","bash",[103,360,361,380,387,394],{"__ignoreMap":113},[117,362,363,367,370,373,376],{"class":119,"line":12},[117,364,366],{"class":365},"sySUi","$",[117,368,369],{"class":134}," swarmctl",[117,371,372],{"class":134}," cluster",[117,374,375],{"class":134}," update",[117,377,379],{"class":378},"sEi1f"," \\\n",[117,381,382,385],{"class":119,"line":21},[117,383,384],{"class":378},"    --autoscale-cpu-threshold=75",[117,386,379],{"class":378},[117,388,389,392],{"class":119,"line":30},[117,390,391],{"class":378},"    --autoscale-max-nodes=10",[117,393,379],{"class":378},[117,395,396],{"class":119,"line":39},[117,397,398],{"class":378},"    --cluster-name=prod-swarm-alpha\n",[81,400,401,402,405],{},"When the system detects a sustained spike, the OpenStack API is triggered to boot a new instance, execute a ",[103,403,404],{},"cloud-init"," script containing the swarm join token, and register the node to the cluster within minutes. This ensures our services remain responsive even under unpredictable loads. We also have alerting tied into our Slack channels for real-time visibility.",[85,407,409],{"id":408},"whats-next","What's Next",[81,411,412],{},"The next iteration involves integrating Consul for service discovery and moving secrets management to Vault. Both bring operational maturity the cluster currently lacks — expect a follow-up post once the migration settles.",[414,415,416],"style",{},"html pre.shiki code .su6XF, html code.shiki .su6XF{--shiki-default:#998418}html pre.shiki code .sYZai, html code.shiki .sYZai{--shiki-default:#999999}html pre.shiki code .sSP4y, html code.shiki .sSP4y{--shiki-default:#B5695977}html pre.shiki code .spphp, html code.shiki .spphp{--shiki-default:#B56959}html pre.shiki code .sbBg2, html code.shiki .sbBg2{--shiki-default:#1E754F}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sySUi, html code.shiki .sySUi{--shiki-default:#59873A}html pre.shiki code .sEi1f, html code.shiki .sEi1f{--shiki-default:#A65E2B}",{"title":113,"searchDepth":21,"depth":21,"links":418},[419,420,421,422],{"id":87,"depth":21,"text":88},{"id":97,"depth":21,"text":98},{"id":345,"depth":21,"text":346},{"id":408,"depth":21,"text":409},"2026-05-14","A deep dive into networking, resource limits, and automated scaling strategies for Docker Swarm on OpenStack.","md",{},"\u002Fblog\u002Fbuilding-swarm-cluster-openstack","5 min",{"title":76,"description":424},"blog\u002Fbuilding-swarm-cluster-openstack",[432,433,434,435],"Docker","OpenStack","DevOps","Infrastructure","\u002Fimages\u002Fthumbnails\u002Fbuilding-swarm-cluster-openstack.png","No_bDZVlSIYDeHZz_sIAaWIwX7hlq0yaVrJPTRnnE8s",1779361989151]