[{"data":1,"prerenderedAt":4071},["ShallowReactive",2],{"blog-current-shopware-plugin-gitlab-pipeline-build-de":3,"blog-previous-shopware-plugin-gitlab-pipeline-build-de":1207,"blog-next-shopware-plugin-gitlab-pipeline-build-de":1218,"blog-alt-de-shopware-plugin-gitlab-pipeline-build-de":1229,"blog-alt-en-shopware-plugin-gitlab-pipeline-build-de":1230,"employee-robert-juzak":1232,"content-query-TVldk4ROTj":1331,"content-query-w8qtEh68yX":2823,"content-query-KtO3wftRle":3986,"related-refs-shopware_devops--de":4021},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"author":10,"image":11,"releaseDate":12,"blogCategories":13,"articleTags":16,"tags":19,"body":22,"_type":1201,"_id":1202,"_source":1203,"_file":1204,"_stem":1205,"_extension":1206},"/blog/shopware-plugin-gitlab-pipeline-build","blog",false,"","Testen, Bauen, und Veröffentlichen eines Shopware 6 Plugins mit GitLab CI - Teil 2: Bauen","Teil 2: Bauen - Verwendung von GitLab zum Testen, Erstellen und Releasen eines Shopware 6 Plugins","robert-juzak","/images/dev-ops-dark.svg","2026-02-26",[14,15],"Was uns bewegt","DevOps",[15,17,18],"Open Source","Shopware",[20,21],"shopware","devops",{"type":23,"children":24,"toc":1197},"root",[25,34,50,63,70,75,113,118,123,143,156,161,182,188,208,575,586,591,1157,1167,1172,1191],{"type":26,"tag":27,"props":28,"children":33},"element","img",{"alt":7,"aspect-ratio":29,"height":30,"object-fit":31,"src":32},"1.78",300,"fill","/blog/shopware-plugin-build+release.png",[],{"type":26,"tag":35,"props":36,"children":37},"p",{},[38,41,48],{"type":39,"value":40},"text","In meinem ",{"type":26,"tag":42,"props":43,"children":45},"a",{"href":44},"/blog/shopware-plugin-gitlab-pipeline-release",[46],{"type":39,"value":47},"vorherigen Post",{"type":39,"value":49}," habe ich beschrieben, wie man ein Shopware 6 Plugin über die GitLab Package Registry ausliefert.",{"type":26,"tag":35,"props":51,"children":52},{},[53,55,61],{"type":39,"value":54},"Wenn wir unser Projekt mit dem ",{"type":26,"tag":42,"props":56,"children":58},{"href":57},"https://developer.shopware.com/docs/products/cli/extension-commands/build.html#building-an-extension",[59],{"type":39,"value":60},"shopware-cli",{"type":39,"value":62}," bauen,\nsucht das Tool in allen Plugins und prüft, ob sie gebaut werden müssen, und tut dies gegebenenfalls. Dies ist ein unnötiger Schritt.",{"type":26,"tag":64,"props":65,"children":67},"h2",{"id":66},"manuelles-bauen",[68],{"type":39,"value":69},"Manuelles Bauen",{"type":26,"tag":35,"props":71,"children":72},{},[73],{"type":39,"value":74},"Das Bauen eines Plugins ist so einfach wie das Ausführen von:",{"type":26,"tag":76,"props":77,"children":81},"pre",{"className":78,"code":79,"language":80,"meta":7,"style":7},"language-shell shiki shiki-themes github-dark github-dark monokai","shopware-cli extension build .\n","shell",[82],{"type":26,"tag":83,"props":84,"children":85},"code",{"__ignoreMap":7},[86],{"type":26,"tag":87,"props":88,"children":91},"span",{"class":89,"line":90},"line",1,[92,97,103,108],{"type":26,"tag":87,"props":93,"children":95},{"style":94},"--shiki-default:#B392F0;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E",[96],{"type":39,"value":60},{"type":26,"tag":87,"props":98,"children":100},{"style":99},"--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74",[101],{"type":39,"value":102}," extension",{"type":26,"tag":87,"props":104,"children":105},{"style":99},[106],{"type":39,"value":107}," build",{"type":26,"tag":87,"props":109,"children":110},{"style":99},[111],{"type":39,"value":112}," .\n",{"type":26,"tag":35,"props":114,"children":115},{},[116],{"type":39,"value":117},"Im Plugin-Root-Verzeichnis.",{"type":26,"tag":35,"props":119,"children":120},{},[121],{"type":39,"value":122},"Es gibt einige Anpassungen, die Sie vornehmen können, wie zum Beispiel:",{"type":26,"tag":124,"props":125,"children":126},"ul",{},[127,133,138],{"type":26,"tag":128,"props":129,"children":130},"li",{},[131],{"type":39,"value":132},"Einschränkung einer Shopware-Version",{"type":26,"tag":128,"props":134,"children":135},{},[136],{"type":39,"value":137},"Angabe zusätzlicher Bundles",{"type":26,"tag":128,"props":139,"children":140},{},[141],{"type":39,"value":142},"Verwendung von esbuild",{"type":26,"tag":35,"props":144,"children":145},{},[146,148,154],{"type":39,"value":147},"Detaillierte Konfigurationen finden Sie in der ",{"type":26,"tag":42,"props":149,"children":151},{"href":150},"https://developer.shopware.com/docs/products/cli/extension-commands/build.html",[152],{"type":39,"value":153},"offiziellen Dokumentation",{"type":39,"value":155},".",{"type":26,"tag":35,"props":157,"children":158},{},[159],{"type":39,"value":160},"Der Build-Prozess erstellt die folgenden Verzeichnisse, die die kompilierten Dateien enthalten:",{"type":26,"tag":124,"props":162,"children":163},{},[164,173],{"type":26,"tag":128,"props":165,"children":166},{},[167],{"type":26,"tag":83,"props":168,"children":170},{"className":169},[],[171],{"type":39,"value":172},"src/Resources/app/storefront/dist/",{"type":26,"tag":128,"props":174,"children":175},{},[176],{"type":26,"tag":83,"props":177,"children":179},{"className":178},[],[180],{"type":39,"value":181},"src/Resources/public/static/",{"type":26,"tag":64,"props":183,"children":185},{"id":184},"build-pipeline",[186],{"type":39,"value":187},"Build-Pipeline",{"type":26,"tag":35,"props":189,"children":190},{},[191,193,198,200,206],{"type":39,"value":192},"Wir verwenden das offizielle ",{"type":26,"tag":83,"props":194,"children":196},{"className":195},[],[197],{"type":39,"value":60},{"type":39,"value":199}," Docker-Image. Um den Prozess zu beschleunigen, nutzen wir das ",{"type":26,"tag":83,"props":201,"children":203},{"className":202},[],[204],{"type":39,"value":205},"CI",{"type":39,"value":207},"-Caching-System.",{"type":26,"tag":76,"props":209,"children":221},{"className":210,"code":211,"filename":212,"highlights":213,"language":220,"meta":7,"style":7},"language-yaml shiki shiki-themes github-dark github-dark monokai","stages:\n  - build\n\nbuild:\n  image:\n    name: ghcr.io/shopware/shopware-cli:latest-php-8.2\n    entrypoint: [\"\"]\n  stage: build\n  variables:\n    COMPOSER_CACHE_DIR: ${CI_PROJECT_DIR}/.composer\n    npm_config_cache: ${CI_PROJECT_DIR}/.npm\n  script:\n    - shopware-cli extension build .\n  cache:\n    - key: $CI_JOB_NAME\n      paths:\n        - $COMPOSER_CACHE_DIR\n        - $npm_config_cache\n  rules:\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: never\n    - if: $CI_COMMIT_BRANCH\n","\u003Cplugin-root>/.gitlab-ci.yml",[214,215,216,217,218,219],6,14,15,16,17,18,"yaml",[222],{"type":26,"tag":83,"props":223,"children":224},{"__ignoreMap":7},[225,240,254,264,277,290,310,334,351,364,382,400,413,426,439,461,474,488,501,514,536,554],{"type":26,"tag":87,"props":226,"children":227},{"class":89,"line":90},[228,234],{"type":26,"tag":87,"props":229,"children":231},{"style":230},"--shiki-default:#85E89D;--shiki-dark:#85E89D;--shiki-sepia:#F92672",[232],{"type":39,"value":233},"stages",{"type":26,"tag":87,"props":235,"children":237},{"style":236},"--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2",[238],{"type":39,"value":239},":\n",{"type":26,"tag":87,"props":241,"children":243},{"class":89,"line":242},2,[244,249],{"type":26,"tag":87,"props":245,"children":246},{"style":236},[247],{"type":39,"value":248},"  - ",{"type":26,"tag":87,"props":250,"children":251},{"style":99},[252],{"type":39,"value":253},"build\n",{"type":26,"tag":87,"props":255,"children":257},{"class":89,"line":256},3,[258],{"type":26,"tag":87,"props":259,"children":261},{"emptyLinePlaceholder":260},true,[262],{"type":39,"value":263},"\n",{"type":26,"tag":87,"props":265,"children":267},{"class":89,"line":266},4,[268,273],{"type":26,"tag":87,"props":269,"children":270},{"style":230},[271],{"type":39,"value":272},"build",{"type":26,"tag":87,"props":274,"children":275},{"style":236},[276],{"type":39,"value":239},{"type":26,"tag":87,"props":278,"children":280},{"class":89,"line":279},5,[281,286],{"type":26,"tag":87,"props":282,"children":283},{"style":230},[284],{"type":39,"value":285},"  image",{"type":26,"tag":87,"props":287,"children":288},{"style":236},[289],{"type":39,"value":239},{"type":26,"tag":87,"props":291,"children":294},{"class":292,"line":214},[89,293],"highlight",[295,300,305],{"type":26,"tag":87,"props":296,"children":297},{"style":230},[298],{"type":39,"value":299},"    name",{"type":26,"tag":87,"props":301,"children":302},{"style":236},[303],{"type":39,"value":304},": ",{"type":26,"tag":87,"props":306,"children":307},{"style":99},[308],{"type":39,"value":309},"ghcr.io/shopware/shopware-cli:latest-php-8.2\n",{"type":26,"tag":87,"props":311,"children":313},{"class":89,"line":312},7,[314,319,324,329],{"type":26,"tag":87,"props":315,"children":316},{"style":230},[317],{"type":39,"value":318},"    entrypoint",{"type":26,"tag":87,"props":320,"children":321},{"style":236},[322],{"type":39,"value":323},": [",{"type":26,"tag":87,"props":325,"children":326},{"style":99},[327],{"type":39,"value":328},"\"\"",{"type":26,"tag":87,"props":330,"children":331},{"style":236},[332],{"type":39,"value":333},"]\n",{"type":26,"tag":87,"props":335,"children":337},{"class":89,"line":336},8,[338,343,347],{"type":26,"tag":87,"props":339,"children":340},{"style":230},[341],{"type":39,"value":342},"  stage",{"type":26,"tag":87,"props":344,"children":345},{"style":236},[346],{"type":39,"value":304},{"type":26,"tag":87,"props":348,"children":349},{"style":99},[350],{"type":39,"value":253},{"type":26,"tag":87,"props":352,"children":354},{"class":89,"line":353},9,[355,360],{"type":26,"tag":87,"props":356,"children":357},{"style":230},[358],{"type":39,"value":359},"  variables",{"type":26,"tag":87,"props":361,"children":362},{"style":236},[363],{"type":39,"value":239},{"type":26,"tag":87,"props":365,"children":367},{"class":89,"line":366},10,[368,373,377],{"type":26,"tag":87,"props":369,"children":370},{"style":230},[371],{"type":39,"value":372},"    COMPOSER_CACHE_DIR",{"type":26,"tag":87,"props":374,"children":375},{"style":236},[376],{"type":39,"value":304},{"type":26,"tag":87,"props":378,"children":379},{"style":99},[380],{"type":39,"value":381},"${CI_PROJECT_DIR}/.composer\n",{"type":26,"tag":87,"props":383,"children":385},{"class":89,"line":384},11,[386,391,395],{"type":26,"tag":87,"props":387,"children":388},{"style":230},[389],{"type":39,"value":390},"    npm_config_cache",{"type":26,"tag":87,"props":392,"children":393},{"style":236},[394],{"type":39,"value":304},{"type":26,"tag":87,"props":396,"children":397},{"style":99},[398],{"type":39,"value":399},"${CI_PROJECT_DIR}/.npm\n",{"type":26,"tag":87,"props":401,"children":403},{"class":89,"line":402},12,[404,409],{"type":26,"tag":87,"props":405,"children":406},{"style":230},[407],{"type":39,"value":408},"  script",{"type":26,"tag":87,"props":410,"children":411},{"style":236},[412],{"type":39,"value":239},{"type":26,"tag":87,"props":414,"children":416},{"class":89,"line":415},13,[417,422],{"type":26,"tag":87,"props":418,"children":419},{"style":236},[420],{"type":39,"value":421},"    - ",{"type":26,"tag":87,"props":423,"children":424},{"style":99},[425],{"type":39,"value":79},{"type":26,"tag":87,"props":427,"children":429},{"class":428,"line":215},[89,293],[430,435],{"type":26,"tag":87,"props":431,"children":432},{"style":230},[433],{"type":39,"value":434},"  cache",{"type":26,"tag":87,"props":436,"children":437},{"style":236},[438],{"type":39,"value":239},{"type":26,"tag":87,"props":440,"children":442},{"class":441,"line":216},[89,293],[443,447,452,456],{"type":26,"tag":87,"props":444,"children":445},{"style":236},[446],{"type":39,"value":421},{"type":26,"tag":87,"props":448,"children":449},{"style":230},[450],{"type":39,"value":451},"key",{"type":26,"tag":87,"props":453,"children":454},{"style":236},[455],{"type":39,"value":304},{"type":26,"tag":87,"props":457,"children":458},{"style":99},[459],{"type":39,"value":460},"$CI_JOB_NAME\n",{"type":26,"tag":87,"props":462,"children":464},{"class":463,"line":217},[89,293],[465,470],{"type":26,"tag":87,"props":466,"children":467},{"style":230},[468],{"type":39,"value":469},"      paths",{"type":26,"tag":87,"props":471,"children":472},{"style":236},[473],{"type":39,"value":239},{"type":26,"tag":87,"props":475,"children":477},{"class":476,"line":218},[89,293],[478,483],{"type":26,"tag":87,"props":479,"children":480},{"style":236},[481],{"type":39,"value":482},"        - ",{"type":26,"tag":87,"props":484,"children":485},{"style":99},[486],{"type":39,"value":487},"$COMPOSER_CACHE_DIR\n",{"type":26,"tag":87,"props":489,"children":491},{"class":490,"line":219},[89,293],[492,496],{"type":26,"tag":87,"props":493,"children":494},{"style":236},[495],{"type":39,"value":482},{"type":26,"tag":87,"props":497,"children":498},{"style":99},[499],{"type":39,"value":500},"$npm_config_cache\n",{"type":26,"tag":87,"props":502,"children":504},{"class":89,"line":503},19,[505,510],{"type":26,"tag":87,"props":506,"children":507},{"style":230},[508],{"type":39,"value":509},"  rules",{"type":26,"tag":87,"props":511,"children":512},{"style":236},[513],{"type":39,"value":239},{"type":26,"tag":87,"props":515,"children":517},{"class":89,"line":516},20,[518,522,527,531],{"type":26,"tag":87,"props":519,"children":520},{"style":236},[521],{"type":39,"value":421},{"type":26,"tag":87,"props":523,"children":524},{"style":230},[525],{"type":39,"value":526},"if",{"type":26,"tag":87,"props":528,"children":529},{"style":236},[530],{"type":39,"value":304},{"type":26,"tag":87,"props":532,"children":533},{"style":99},[534],{"type":39,"value":535},"$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n",{"type":26,"tag":87,"props":537,"children":539},{"class":89,"line":538},21,[540,545,549],{"type":26,"tag":87,"props":541,"children":542},{"style":230},[543],{"type":39,"value":544},"      when",{"type":26,"tag":87,"props":546,"children":547},{"style":236},[548],{"type":39,"value":304},{"type":26,"tag":87,"props":550,"children":551},{"style":99},[552],{"type":39,"value":553},"never\n",{"type":26,"tag":87,"props":555,"children":557},{"class":89,"line":556},22,[558,562,566,570],{"type":26,"tag":87,"props":559,"children":560},{"style":236},[561],{"type":39,"value":421},{"type":26,"tag":87,"props":563,"children":564},{"style":230},[565],{"type":39,"value":526},{"type":26,"tag":87,"props":567,"children":568},{"style":236},[569],{"type":39,"value":304},{"type":26,"tag":87,"props":571,"children":572},{"style":99},[573],{"type":39,"value":574},"$CI_COMMIT_BRANCH\n",{"type":26,"tag":35,"props":576,"children":577},{},[578,580,585],{"type":39,"value":579},"Kombinieren wir dies mit unserer Release-Pipeline aus dem ",{"type":26,"tag":42,"props":581,"children":583},{"href":582},"/blog/shopware-plugin-gitlab-pipeline-release#mit-semantic-release",[584],{"type":39,"value":47},{"type":39,"value":155},{"type":26,"tag":35,"props":587,"children":588},{},[589],{"type":39,"value":590},"Es ist wichtig, die gebauten Artefakte an den nächsten Job zu übergeben.",{"type":26,"tag":76,"props":592,"children":596},{"className":210,"code":593,"filename":212,"highlights":594,"language":220,"meta":7,"style":7},"stages:\n  - release\n  - build\n\nbuild:\n  image:\n    name: ghcr.io/shopware/shopware-cli:latest-php-8.2\n    entrypoint: [\"\"]\n  stage: build\n  variables:\n    COMPOSER_CACHE_DIR: ${CI_PROJECT_DIR}/.composer\n    npm_config_cache: ${CI_PROJECT_DIR}/.npm\n  script:\n    - shopware-cli extension build .\n  cache:\n    - key: $CI_JOB_NAME\n      paths:\n        - $COMPOSER_CACHE_DIR\n        - $npm_config_cache\n  artifacts:\n    paths:\n      - src/Resources/public\n      - src/Storefront/Resources/public\n  rules:\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: never\n    - if: $CI_COMMIT_BRANCH\n\nrelease:\n  stage: release\n  image:\n    name: ghcr.io/voxpupuli/semantic-release:latest\n    entrypoint: [\"\"]\n  interruptible: true\n  script:\n    - /docker-entrypoint.sh\n  rules:\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: never\n    - if: $CI_COMMIT_BRANCH\n",[516,538,556,595],23,[597],{"type":26,"tag":83,"props":598,"children":599},{"__ignoreMap":7},[600,611,623,634,641,652,663,678,697,712,723,738,753,764,775,786,805,816,827,838,851,864,878,891,903,923,939,959,967,980,996,1008,1025,1045,1064,1076,1089,1101,1121,1137],{"type":26,"tag":87,"props":601,"children":602},{"class":89,"line":90},[603,607],{"type":26,"tag":87,"props":604,"children":605},{"style":230},[606],{"type":39,"value":233},{"type":26,"tag":87,"props":608,"children":609},{"style":236},[610],{"type":39,"value":239},{"type":26,"tag":87,"props":612,"children":613},{"class":89,"line":242},[614,618],{"type":26,"tag":87,"props":615,"children":616},{"style":236},[617],{"type":39,"value":248},{"type":26,"tag":87,"props":619,"children":620},{"style":99},[621],{"type":39,"value":622},"release\n",{"type":26,"tag":87,"props":624,"children":625},{"class":89,"line":256},[626,630],{"type":26,"tag":87,"props":627,"children":628},{"style":236},[629],{"type":39,"value":248},{"type":26,"tag":87,"props":631,"children":632},{"style":99},[633],{"type":39,"value":253},{"type":26,"tag":87,"props":635,"children":636},{"class":89,"line":266},[637],{"type":26,"tag":87,"props":638,"children":639},{"emptyLinePlaceholder":260},[640],{"type":39,"value":263},{"type":26,"tag":87,"props":642,"children":643},{"class":89,"line":279},[644,648],{"type":26,"tag":87,"props":645,"children":646},{"style":230},[647],{"type":39,"value":272},{"type":26,"tag":87,"props":649,"children":650},{"style":236},[651],{"type":39,"value":239},{"type":26,"tag":87,"props":653,"children":654},{"class":89,"line":214},[655,659],{"type":26,"tag":87,"props":656,"children":657},{"style":230},[658],{"type":39,"value":285},{"type":26,"tag":87,"props":660,"children":661},{"style":236},[662],{"type":39,"value":239},{"type":26,"tag":87,"props":664,"children":665},{"class":89,"line":312},[666,670,674],{"type":26,"tag":87,"props":667,"children":668},{"style":230},[669],{"type":39,"value":299},{"type":26,"tag":87,"props":671,"children":672},{"style":236},[673],{"type":39,"value":304},{"type":26,"tag":87,"props":675,"children":676},{"style":99},[677],{"type":39,"value":309},{"type":26,"tag":87,"props":679,"children":680},{"class":89,"line":336},[681,685,689,693],{"type":26,"tag":87,"props":682,"children":683},{"style":230},[684],{"type":39,"value":318},{"type":26,"tag":87,"props":686,"children":687},{"style":236},[688],{"type":39,"value":323},{"type":26,"tag":87,"props":690,"children":691},{"style":99},[692],{"type":39,"value":328},{"type":26,"tag":87,"props":694,"children":695},{"style":236},[696],{"type":39,"value":333},{"type":26,"tag":87,"props":698,"children":699},{"class":89,"line":353},[700,704,708],{"type":26,"tag":87,"props":701,"children":702},{"style":230},[703],{"type":39,"value":342},{"type":26,"tag":87,"props":705,"children":706},{"style":236},[707],{"type":39,"value":304},{"type":26,"tag":87,"props":709,"children":710},{"style":99},[711],{"type":39,"value":253},{"type":26,"tag":87,"props":713,"children":714},{"class":89,"line":366},[715,719],{"type":26,"tag":87,"props":716,"children":717},{"style":230},[718],{"type":39,"value":359},{"type":26,"tag":87,"props":720,"children":721},{"style":236},[722],{"type":39,"value":239},{"type":26,"tag":87,"props":724,"children":725},{"class":89,"line":384},[726,730,734],{"type":26,"tag":87,"props":727,"children":728},{"style":230},[729],{"type":39,"value":372},{"type":26,"tag":87,"props":731,"children":732},{"style":236},[733],{"type":39,"value":304},{"type":26,"tag":87,"props":735,"children":736},{"style":99},[737],{"type":39,"value":381},{"type":26,"tag":87,"props":739,"children":740},{"class":89,"line":402},[741,745,749],{"type":26,"tag":87,"props":742,"children":743},{"style":230},[744],{"type":39,"value":390},{"type":26,"tag":87,"props":746,"children":747},{"style":236},[748],{"type":39,"value":304},{"type":26,"tag":87,"props":750,"children":751},{"style":99},[752],{"type":39,"value":399},{"type":26,"tag":87,"props":754,"children":755},{"class":89,"line":415},[756,760],{"type":26,"tag":87,"props":757,"children":758},{"style":230},[759],{"type":39,"value":408},{"type":26,"tag":87,"props":761,"children":762},{"style":236},[763],{"type":39,"value":239},{"type":26,"tag":87,"props":765,"children":766},{"class":89,"line":215},[767,771],{"type":26,"tag":87,"props":768,"children":769},{"style":236},[770],{"type":39,"value":421},{"type":26,"tag":87,"props":772,"children":773},{"style":99},[774],{"type":39,"value":79},{"type":26,"tag":87,"props":776,"children":777},{"class":89,"line":216},[778,782],{"type":26,"tag":87,"props":779,"children":780},{"style":230},[781],{"type":39,"value":434},{"type":26,"tag":87,"props":783,"children":784},{"style":236},[785],{"type":39,"value":239},{"type":26,"tag":87,"props":787,"children":788},{"class":89,"line":217},[789,793,797,801],{"type":26,"tag":87,"props":790,"children":791},{"style":236},[792],{"type":39,"value":421},{"type":26,"tag":87,"props":794,"children":795},{"style":230},[796],{"type":39,"value":451},{"type":26,"tag":87,"props":798,"children":799},{"style":236},[800],{"type":39,"value":304},{"type":26,"tag":87,"props":802,"children":803},{"style":99},[804],{"type":39,"value":460},{"type":26,"tag":87,"props":806,"children":807},{"class":89,"line":218},[808,812],{"type":26,"tag":87,"props":809,"children":810},{"style":230},[811],{"type":39,"value":469},{"type":26,"tag":87,"props":813,"children":814},{"style":236},[815],{"type":39,"value":239},{"type":26,"tag":87,"props":817,"children":818},{"class":89,"line":219},[819,823],{"type":26,"tag":87,"props":820,"children":821},{"style":236},[822],{"type":39,"value":482},{"type":26,"tag":87,"props":824,"children":825},{"style":99},[826],{"type":39,"value":487},{"type":26,"tag":87,"props":828,"children":829},{"class":89,"line":503},[830,834],{"type":26,"tag":87,"props":831,"children":832},{"style":236},[833],{"type":39,"value":482},{"type":26,"tag":87,"props":835,"children":836},{"style":99},[837],{"type":39,"value":500},{"type":26,"tag":87,"props":839,"children":841},{"class":840,"line":516},[89,293],[842,847],{"type":26,"tag":87,"props":843,"children":844},{"style":230},[845],{"type":39,"value":846},"  artifacts",{"type":26,"tag":87,"props":848,"children":849},{"style":236},[850],{"type":39,"value":239},{"type":26,"tag":87,"props":852,"children":854},{"class":853,"line":538},[89,293],[855,860],{"type":26,"tag":87,"props":856,"children":857},{"style":230},[858],{"type":39,"value":859},"    paths",{"type":26,"tag":87,"props":861,"children":862},{"style":236},[863],{"type":39,"value":239},{"type":26,"tag":87,"props":865,"children":867},{"class":866,"line":556},[89,293],[868,873],{"type":26,"tag":87,"props":869,"children":870},{"style":236},[871],{"type":39,"value":872},"      - ",{"type":26,"tag":87,"props":874,"children":875},{"style":99},[876],{"type":39,"value":877},"src/Resources/public\n",{"type":26,"tag":87,"props":879,"children":881},{"class":880,"line":595},[89,293],[882,886],{"type":26,"tag":87,"props":883,"children":884},{"style":236},[885],{"type":39,"value":872},{"type":26,"tag":87,"props":887,"children":888},{"style":99},[889],{"type":39,"value":890},"src/Storefront/Resources/public\n",{"type":26,"tag":87,"props":892,"children":894},{"class":89,"line":893},24,[895,899],{"type":26,"tag":87,"props":896,"children":897},{"style":230},[898],{"type":39,"value":509},{"type":26,"tag":87,"props":900,"children":901},{"style":236},[902],{"type":39,"value":239},{"type":26,"tag":87,"props":904,"children":906},{"class":89,"line":905},25,[907,911,915,919],{"type":26,"tag":87,"props":908,"children":909},{"style":236},[910],{"type":39,"value":421},{"type":26,"tag":87,"props":912,"children":913},{"style":230},[914],{"type":39,"value":526},{"type":26,"tag":87,"props":916,"children":917},{"style":236},[918],{"type":39,"value":304},{"type":26,"tag":87,"props":920,"children":921},{"style":99},[922],{"type":39,"value":535},{"type":26,"tag":87,"props":924,"children":926},{"class":89,"line":925},26,[927,931,935],{"type":26,"tag":87,"props":928,"children":929},{"style":230},[930],{"type":39,"value":544},{"type":26,"tag":87,"props":932,"children":933},{"style":236},[934],{"type":39,"value":304},{"type":26,"tag":87,"props":936,"children":937},{"style":99},[938],{"type":39,"value":553},{"type":26,"tag":87,"props":940,"children":942},{"class":89,"line":941},27,[943,947,951,955],{"type":26,"tag":87,"props":944,"children":945},{"style":236},[946],{"type":39,"value":421},{"type":26,"tag":87,"props":948,"children":949},{"style":230},[950],{"type":39,"value":526},{"type":26,"tag":87,"props":952,"children":953},{"style":236},[954],{"type":39,"value":304},{"type":26,"tag":87,"props":956,"children":957},{"style":99},[958],{"type":39,"value":574},{"type":26,"tag":87,"props":960,"children":962},{"class":89,"line":961},28,[963],{"type":26,"tag":87,"props":964,"children":965},{"emptyLinePlaceholder":260},[966],{"type":39,"value":263},{"type":26,"tag":87,"props":968,"children":970},{"class":89,"line":969},29,[971,976],{"type":26,"tag":87,"props":972,"children":973},{"style":230},[974],{"type":39,"value":975},"release",{"type":26,"tag":87,"props":977,"children":978},{"style":236},[979],{"type":39,"value":239},{"type":26,"tag":87,"props":981,"children":983},{"class":89,"line":982},30,[984,988,992],{"type":26,"tag":87,"props":985,"children":986},{"style":230},[987],{"type":39,"value":342},{"type":26,"tag":87,"props":989,"children":990},{"style":236},[991],{"type":39,"value":304},{"type":26,"tag":87,"props":993,"children":994},{"style":99},[995],{"type":39,"value":622},{"type":26,"tag":87,"props":997,"children":999},{"class":89,"line":998},31,[1000,1004],{"type":26,"tag":87,"props":1001,"children":1002},{"style":230},[1003],{"type":39,"value":285},{"type":26,"tag":87,"props":1005,"children":1006},{"style":236},[1007],{"type":39,"value":239},{"type":26,"tag":87,"props":1009,"children":1011},{"class":89,"line":1010},32,[1012,1016,1020],{"type":26,"tag":87,"props":1013,"children":1014},{"style":230},[1015],{"type":39,"value":299},{"type":26,"tag":87,"props":1017,"children":1018},{"style":236},[1019],{"type":39,"value":304},{"type":26,"tag":87,"props":1021,"children":1022},{"style":99},[1023],{"type":39,"value":1024},"ghcr.io/voxpupuli/semantic-release:latest\n",{"type":26,"tag":87,"props":1026,"children":1028},{"class":89,"line":1027},33,[1029,1033,1037,1041],{"type":26,"tag":87,"props":1030,"children":1031},{"style":230},[1032],{"type":39,"value":318},{"type":26,"tag":87,"props":1034,"children":1035},{"style":236},[1036],{"type":39,"value":323},{"type":26,"tag":87,"props":1038,"children":1039},{"style":99},[1040],{"type":39,"value":328},{"type":26,"tag":87,"props":1042,"children":1043},{"style":236},[1044],{"type":39,"value":333},{"type":26,"tag":87,"props":1046,"children":1048},{"class":89,"line":1047},34,[1049,1054,1058],{"type":26,"tag":87,"props":1050,"children":1051},{"style":230},[1052],{"type":39,"value":1053},"  interruptible",{"type":26,"tag":87,"props":1055,"children":1056},{"style":236},[1057],{"type":39,"value":304},{"type":26,"tag":87,"props":1059,"children":1061},{"style":1060},"--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF",[1062],{"type":39,"value":1063},"true\n",{"type":26,"tag":87,"props":1065,"children":1067},{"class":89,"line":1066},35,[1068,1072],{"type":26,"tag":87,"props":1069,"children":1070},{"style":230},[1071],{"type":39,"value":408},{"type":26,"tag":87,"props":1073,"children":1074},{"style":236},[1075],{"type":39,"value":239},{"type":26,"tag":87,"props":1077,"children":1079},{"class":89,"line":1078},36,[1080,1084],{"type":26,"tag":87,"props":1081,"children":1082},{"style":236},[1083],{"type":39,"value":421},{"type":26,"tag":87,"props":1085,"children":1086},{"style":99},[1087],{"type":39,"value":1088},"/docker-entrypoint.sh\n",{"type":26,"tag":87,"props":1090,"children":1092},{"class":89,"line":1091},37,[1093,1097],{"type":26,"tag":87,"props":1094,"children":1095},{"style":230},[1096],{"type":39,"value":509},{"type":26,"tag":87,"props":1098,"children":1099},{"style":236},[1100],{"type":39,"value":239},{"type":26,"tag":87,"props":1102,"children":1104},{"class":89,"line":1103},38,[1105,1109,1113,1117],{"type":26,"tag":87,"props":1106,"children":1107},{"style":236},[1108],{"type":39,"value":421},{"type":26,"tag":87,"props":1110,"children":1111},{"style":230},[1112],{"type":39,"value":526},{"type":26,"tag":87,"props":1114,"children":1115},{"style":236},[1116],{"type":39,"value":304},{"type":26,"tag":87,"props":1118,"children":1119},{"style":99},[1120],{"type":39,"value":535},{"type":26,"tag":87,"props":1122,"children":1124},{"class":89,"line":1123},39,[1125,1129,1133],{"type":26,"tag":87,"props":1126,"children":1127},{"style":230},[1128],{"type":39,"value":544},{"type":26,"tag":87,"props":1130,"children":1131},{"style":236},[1132],{"type":39,"value":304},{"type":26,"tag":87,"props":1134,"children":1135},{"style":99},[1136],{"type":39,"value":553},{"type":26,"tag":87,"props":1138,"children":1140},{"class":89,"line":1139},40,[1141,1145,1149,1153],{"type":26,"tag":87,"props":1142,"children":1143},{"style":236},[1144],{"type":39,"value":421},{"type":26,"tag":87,"props":1146,"children":1147},{"style":230},[1148],{"type":39,"value":526},{"type":26,"tag":87,"props":1150,"children":1151},{"style":236},[1152],{"type":39,"value":304},{"type":26,"tag":87,"props":1154,"children":1155},{"style":99},[1156],{"type":39,"value":574},{"type":26,"tag":35,"props":1158,"children":1159},{},[1160],{"type":26,"tag":87,"props":1161,"children":1164},{"className":1162},[1163],"text-h2",[1165],{"type":39,"value":1166},"Das war's!",{"type":26,"tag":35,"props":1168,"children":1169},{},[1170],{"type":39,"value":1171},"Dies wird:",{"type":26,"tag":1173,"props":1174,"children":1175},"ol",{},[1176,1181,1186],{"type":26,"tag":128,"props":1177,"children":1178},{},[1179],{"type":39,"value":1180},"Alle Assets bauen",{"type":26,"tag":128,"props":1182,"children":1183},{},[1184],{"type":39,"value":1185},"Sie an den zweiten Job übergeben",{"type":26,"tag":128,"props":1187,"children":1188},{},[1189],{"type":39,"value":1190},"Den Release-Prozess wie zuvor beschrieben ausführen",{"type":26,"tag":1192,"props":1193,"children":1194},"style",{},[1195],{"type":39,"value":1196},"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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}",{"title":7,"searchDepth":242,"depth":242,"links":1198},[1199,1200],{"id":66,"depth":242,"text":69},{"id":184,"depth":242,"text":187},"markdown","common:blog:19.shopware-plugin-gitlab-pipeline-build.md","common","blog/19.shopware-plugin-gitlab-pipeline-build.md","blog/19.shopware-plugin-gitlab-pipeline-build","md",{"_path":1208,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1209,"description":1210,"author":10,"image":11,"releaseDate":1211,"blogCategories":1212,"articleTags":1213,"tags":1214,"_type":1201,"_id":1215,"_source":1203,"_file":1216,"_stem":1217,"_extension":1206},"/blog/gitops-docker-renovate","Softwareverwaltung mit GitLab, Renovate Bot und Docker","Software auf einem Server zu verwalten ist nicht einfach. Oder doch?","2025-10-30",[14,15],[15,17],[21],"common:blog:17.gitops-docker-renovate.md","blog/17.gitops-docker-renovate.md","blog/17.gitops-docker-renovate",{"_path":1219,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1220,"description":1221,"author":10,"image":11,"releaseDate":1222,"blogCategories":1223,"articleTags":1224,"tags":1225,"_type":1201,"_id":1226,"_source":1203,"_file":1227,"_stem":1228,"_extension":1206},"/blog/traefik-magic","Verwendung von Traefik als Reverse Proxy - Convention over Configuration","Wie man den Traefik Reverse Proxy so konfiguriert, dass man auf Traefik-spezifische Labels verzichten kann und automatisch Subdomains passend zum Namen des Compose-Projekts geroutet werden.","2026-03-13",[14,15],[15],[21],"common:blog:21.traefik-magic.md","blog/21.traefik-magic.md","blog/21.traefik-magic",{"_path":4},{"_path":1231},"/en/blog/shopware-plugin-gitlab-pipeline-build",{"_path":1233,"_dir":1234,"_draft":6,"_partial":6,"_locale":7,"slug":10,"teams":1235,"primaryTeam":1237,"firstName":1238,"lastName":1239,"prefixTitle":7,"suffixTitle":1240,"education":1241,"role":1246,"workingSince":1251,"inTheCompanySince":1252,"techSkills":1253,"skills":1292,"projects":1310,"contactDetails":1320,"_image":1324,"image":1325,"_id":1326,"_type":1327,"title":1328,"_source":1234,"_file":1329,"_stem":1330,"_extension":1327},"/employees/robert-juzak","employees",[1236,1237],"appDev","devOps","Robert","Juzak","B.Sc.",[1242],[1243,1244,1245],"Bachelor of Computer Science","Technische Universität Breslau","2016",[1247,1248,1249,1250],"softwareDeveloper","fullstackDeveloper","admin","consultant","2015","2018",[1254,1258,1260,1263,1266,1269,1271,1274,1277,1281,1284,1286,1289],{"name":1255,"level":1256,"icon":1257},"Docker","expert","/images/Docker.svg",{"name":1259,"level":1256},"GitLab",{"name":1261,"level":1256,"icon":1262},"Kubernetes","/images/Kubernetes.svg",{"name":1264,"level":1256,"icon":1265},"PHPUnit","/images/PHP-Unit.svg",{"name":1267,"level":1256,"icon":1268},"Portainer","/images/Portainer.svg",{"name":1270,"level":1256},"Sentry",{"name":1272,"level":1256,"icon":1273},"Sonarqube","/images/Sonarqube.svg",{"name":1275,"level":1256,"icon":1276},"Linux","/images/linux_os-mono.svg",{"name":1278,"level":1279,"icon":1280},"CSS","advanced","/images/css.svg",{"name":1282,"level":1279,"icon":1283},"HTML","/images/html.svg",{"name":1285,"level":1279},"PHP",{"name":1287,"level":1279,"icon":1288},"SQL","/images/SQL.svg",{"name":1290,"level":1279,"icon":1291},"VueJS","/images/vuejs.svg",[1293,1295,1297,1298,1300,1302,1304,1306,1308],{"name":1294,"level":1256},"CI/CD",{"name":1296,"level":1256},"qualityAssurance",{"name":1237,"level":1256},{"name":1299,"level":1256},"testDrivenBugfix",{"name":1301,"level":1256},"testDrivenDevelopment",{"name":1303,"level":1279},"accessibility",{"name":1305,"level":1279},"databases",{"name":1307,"level":1279},"linuxServerAdministration",{"name":1309,"level":1279},"softwareArchitect",[1311,1316,1318],{"project":1312,"position":1313},"Herole",[1314,1315],"Dev-Ops","Frontend Developer",{"project":1317,"position":1315},"Huawei-Calibration-aaS",{"project":1319,"position":1315},"Huawei-Inspect-3D",{"eMail":1321,"phone":1322,"visibility":1323},"robert.juzak@helmundwalter.de","+49 351 799 035 26","1","images/employees/Portraits/robert_juzak.webp","images/employees/Portraits/RobertJuzak_MS.webp","employees:employees:6.robert-juzak.json","json","Robert Juzak","employees/6.robert-juzak.json","employees/6.robert-juzak",{"_path":1208,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1209,"description":1210,"author":10,"image":11,"releaseDate":1211,"blogCategories":1332,"articleTags":1333,"tags":1334,"body":1335,"_type":1201,"_id":1215,"_source":1203,"_file":1216,"_stem":1217,"_extension":1206},[14,15],[15,17],[21],{"type":23,"children":1336,"toc":2816},[1337,1342,1347,1352,1357,1362,1380,1385,1427,1433,1446,1459,1464,1470,1481,1494,1503,1509,1514,1627,2151,2187,2200,2204,2209,2372,2385,2391,2396,2474,2479,2485,2490,2503,2516,2550,2577,2589,2608,2621,2624,2629,2642,2662,2667,2672,2793,2812],{"type":26,"tag":35,"props":1338,"children":1339},{},[1340],{"type":39,"value":1341},"Die Verwaltung eines Servers mit mehreren Diensten kann knifflig sein. Nicht jede Software ist miteinander kompatibel. Beispielsweise gibt es Anforderungen an Datenbank- oder PHP-Versionen.",{"type":26,"tag":35,"props":1343,"children":1344},{},[1345],{"type":39,"value":1346},"Außerdem sollte die Software auf dem neuesten Stand sein, um mögliche Sicherheitsrisiken zu minimieren.",{"type":26,"tag":35,"props":1348,"children":1349},{},[1350],{"type":39,"value":1351},"Es gibt viele Möglichkeiten, damit umzugehen, wie etwa Ansible, Chef usw.",{"type":26,"tag":35,"props":1353,"children":1354},{},[1355],{"type":39,"value":1356},"Unser Ziel war eine einfach zu bedienende, automatisierte und kostenlose Lösung.",{"type":26,"tag":35,"props":1358,"children":1359},{},[1360],{"type":39,"value":1361},"Hier sind die Ziele:",{"type":26,"tag":124,"props":1363,"children":1364},{},[1365,1370,1375],{"type":26,"tag":128,"props":1366,"children":1367},{},[1368],{"type":39,"value":1369},"den GitOps-Ansatz nutzen, um die Konfiguration zu speichern und per Versionskontrolle nachvollziehbar zu machen",{"type":26,"tag":128,"props":1371,"children":1372},{},[1373],{"type":39,"value":1374},"Container verwenden, um die Software auszuführen",{"type":26,"tag":128,"props":1376,"children":1377},{},[1378],{"type":39,"value":1379},"Sicherheitsupdates automatisch ausspielen und Minor-/Major-Updates per Opt-in steuern",{"type":26,"tag":35,"props":1381,"children":1382},{},[1383],{"type":39,"value":1384},"Wir haben uns am Ende für den folgenden Stack entschieden:",{"type":26,"tag":124,"props":1386,"children":1387},{},[1388,1406,1416],{"type":26,"tag":128,"props":1389,"children":1390},{},[1391,1396,1398,1404],{"type":26,"tag":42,"props":1392,"children":1394},{"href":1393},"https://www.docker.com/",[1395],{"type":39,"value":1255},{"type":39,"value":1397}," und ",{"type":26,"tag":42,"props":1399,"children":1401},{"href":1400},"https://docs.docker.com/compose/",[1402],{"type":39,"value":1403},"Docker Compose",{"type":39,"value":1405}," zum Verwalten der Software",{"type":26,"tag":128,"props":1407,"children":1408},{},[1409,1414],{"type":26,"tag":42,"props":1410,"children":1412},{"href":1411},"https://about.gitlab.com/",[1413],{"type":39,"value":1259},{"type":39,"value":1415}," zum Speichern aller Compose-Dateien",{"type":26,"tag":128,"props":1417,"children":1418},{},[1419,1425],{"type":26,"tag":42,"props":1420,"children":1422},{"href":1421},"https://docs.renovatebot.com",[1423],{"type":39,"value":1424},"Renovate Bot",{"type":39,"value":1426},", um die Software aktuell zu halten",{"type":26,"tag":64,"props":1428,"children":1430},{"id":1429},"über-den-stack",[1431],{"type":39,"value":1432},"Über den Stack",{"type":26,"tag":35,"props":1434,"children":1435},{},[1436,1438,1444],{"type":39,"value":1437},"Wir verwenden Docker bereits seit einiger Zeit in der Produktion. Je nach Situation erstellen wir die Compose-Datei direkt auf dem Server, verwalten sie über Portainer oder übertragen sie per ",{"type":26,"tag":83,"props":1439,"children":1441},{"className":1440},[],[1442],{"type":39,"value":1443},"scp",{"type":39,"value":1445}," in eine Pipeline.",{"type":26,"tag":35,"props":1447,"children":1448},{},[1449,1451,1457],{"type":39,"value":1450},"GitLab ist unser primäres Tool für die Versionskontrolle. Zusätzlich kümmert sich ein ",{"type":26,"tag":42,"props":1452,"children":1454},{"href":1453},"https://docs.gitlab.com/runner/",[1455],{"type":39,"value":1456},"GitLab Runner",{"type":39,"value":1458}," um das Ausführen der Pipelines.",{"type":26,"tag":35,"props":1460,"children":1461},{},[1462],{"type":39,"value":1463},"Renovate automatisiert Abhängigkeitsupdates. PHP, Go, Python, Docker – um nur ein paar zu nennen. Wir nutzen es bereits in verschiedenen Projekten.",{"type":26,"tag":64,"props":1465,"children":1467},{"id":1466},"container-mit-docker-und-docker-compose",[1468],{"type":39,"value":1469},"Container mit Docker und Docker Compose",{"type":26,"tag":35,"props":1471,"children":1472},{},[1473,1475,1480],{"type":39,"value":1474},"Der Hauptgrund, warum wir Docker gewählt haben, ist die Möglichkeit, auf einen remoten Docker-Host zuzugreifen und Docker-Befehle ausführen zu können.\nWeitere Informationen findest du in der ",{"type":26,"tag":42,"props":1476,"children":1478},{"href":1477},"https://docs.docker.com/reference/cli/docker/#host",[1479],{"type":39,"value":153},{"type":39,"value":155},{"type":26,"tag":35,"props":1482,"children":1483},{},[1484,1486,1492],{"type":39,"value":1485},"Wir verwenden ",{"type":26,"tag":83,"props":1487,"children":1489},{"className":1488},[],[1490],{"type":39,"value":1491},"ssh",{"type":39,"value":1493},", um auf unseren Zielserver zuzugreifen.",{"type":26,"tag":35,"props":1495,"children":1496},{},[1497],{"type":26,"tag":83,"props":1498,"children":1500},{"className":1499},[],[1501],{"type":39,"value":1502},"DOCKER_HOST=ssh://[username@]\u003CIP or host>[:port] docker compose up --wait",{"type":26,"tag":64,"props":1504,"children":1506},{"id":1505},"gitops-mit-gitlab",[1507],{"type":39,"value":1508},"GitOps mit GitLab",{"type":26,"tag":35,"props":1510,"children":1511},{},[1512],{"type":39,"value":1513},"Die Idee hinter GitOps ist, ein Git-Repository zur Ablage der Konfiguration zu verwenden. Hier ein Beispiel:",{"type":26,"tag":76,"props":1515,"children":1517},{"className":78,"code":1516,"language":80,"meta":7,"style":7},".\n├──.gitlab-ci.yml             # Pipeline-Definition\n├── renovate.json             # Renovate-Konfiguration\n├── nextcloud\n│   ├── docker-compose.yml   # Nextcloud Datei-Hosting und Zusammenarbeit\n└── traefik\n    └── docker-compose.yml   # Traefik Reverse-Proxy-Konfiguration\n\n",[1518],{"type":26,"tag":83,"props":1519,"children":1520},{"__ignoreMap":7},[1521,1530,1544,1562,1574,1597,1610],{"type":26,"tag":87,"props":1522,"children":1523},{"class":89,"line":90},[1524],{"type":26,"tag":87,"props":1525,"children":1527},{"style":1526},"--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-sepia:#66D9EF",[1528],{"type":39,"value":1529},".\n",{"type":26,"tag":87,"props":1531,"children":1532},{"class":89,"line":242},[1533,1538],{"type":26,"tag":87,"props":1534,"children":1535},{"style":94},[1536],{"type":39,"value":1537},"├──.gitlab-ci.yml",{"type":26,"tag":87,"props":1539,"children":1541},{"style":1540},"--shiki-default:#6A737D;--shiki-dark:#6A737D;--shiki-sepia:#88846F",[1542],{"type":39,"value":1543},"             # Pipeline-Definition\n",{"type":26,"tag":87,"props":1545,"children":1546},{"class":89,"line":256},[1547,1552,1557],{"type":26,"tag":87,"props":1548,"children":1549},{"style":94},[1550],{"type":39,"value":1551},"├──",{"type":26,"tag":87,"props":1553,"children":1554},{"style":99},[1555],{"type":39,"value":1556}," renovate.json",{"type":26,"tag":87,"props":1558,"children":1559},{"style":1540},[1560],{"type":39,"value":1561},"             # Renovate-Konfiguration\n",{"type":26,"tag":87,"props":1563,"children":1564},{"class":89,"line":266},[1565,1569],{"type":26,"tag":87,"props":1566,"children":1567},{"style":94},[1568],{"type":39,"value":1551},{"type":26,"tag":87,"props":1570,"children":1571},{"style":99},[1572],{"type":39,"value":1573}," nextcloud\n",{"type":26,"tag":87,"props":1575,"children":1576},{"class":89,"line":279},[1577,1582,1587,1592],{"type":26,"tag":87,"props":1578,"children":1579},{"style":94},[1580],{"type":39,"value":1581},"│",{"type":26,"tag":87,"props":1583,"children":1584},{"style":99},[1585],{"type":39,"value":1586},"   ├──",{"type":26,"tag":87,"props":1588,"children":1589},{"style":99},[1590],{"type":39,"value":1591}," docker-compose.yml",{"type":26,"tag":87,"props":1593,"children":1594},{"style":1540},[1595],{"type":39,"value":1596},"   # Nextcloud Datei-Hosting und Zusammenarbeit\n",{"type":26,"tag":87,"props":1598,"children":1599},{"class":89,"line":214},[1600,1605],{"type":26,"tag":87,"props":1601,"children":1602},{"style":94},[1603],{"type":39,"value":1604},"└──",{"type":26,"tag":87,"props":1606,"children":1607},{"style":99},[1608],{"type":39,"value":1609}," traefik\n",{"type":26,"tag":87,"props":1611,"children":1612},{"class":89,"line":312},[1613,1618,1622],{"type":26,"tag":87,"props":1614,"children":1615},{"style":94},[1616],{"type":39,"value":1617},"    └──",{"type":26,"tag":87,"props":1619,"children":1620},{"style":99},[1621],{"type":39,"value":1591},{"type":26,"tag":87,"props":1623,"children":1624},{"style":1540},[1625],{"type":39,"value":1626},"   # Traefik Reverse-Proxy-Konfiguration\n",{"type":26,"tag":76,"props":1628,"children":1631},{"className":210,"code":1629,"filename":1630,"language":220,"meta":7,"style":7},"volumes:\n  nextcloud:\n  db:\n\nservices:\n  db:\n    image: mariadb:11.8\n    restart: unless-stopped\n    volumes:\n      - db:/var/lib/mysql\n    environment:\n      - MARIADB_ROOT_PASSWORD=${NEXTCLOUD_MARIADB_ROOT_PASSWORD:?error}\n      - MARIADB_PASSWORD=${NEXTCLOUD_MARIADB_PASSWORD:?error}\n      - MARIADB_DATABASE=nextcloud\n      - MARIADB_USER=nextcloud\n    command:\n      - --transaction-isolation=READ-COMMITTED\n      - --log-bin=binlog\n      - --binlog-format=ROW\n    healthcheck:\n      test: [\"CMD\", \"healthcheck.sh\", \"--connect\", \"--innodb_initialized\"]\n      interval: 15s\n      timeout: 5s\n      retries: 6\n\n  nextcloud:\n    image: nextcloud:32.0.0\n    restart: unless-stopped\n    depends_on:\n      db:\n        condition: service_healthy\n    volumes:\n      - nextcloud:/var/www/html\n    environment:\n      - MYSQL_PASSWORD=${NEXTCLOUD_MARIADB_PASSWORD:?error}\n      - MYSQL_DATABASE=nextcloud\n      - MYSQL_USER=nextcloud\n      - MYSQL_HOST=db\n","nextcloud/docker-compose.yaml",[1632],{"type":26,"tag":83,"props":1633,"children":1634},{"__ignoreMap":7},[1635,1647,1659,1671,1678,1690,1701,1718,1735,1747,1759,1771,1783,1795,1807,1819,1831,1843,1855,1867,1879,1928,1945,1962,1979,1986,1997,2013,2028,2040,2052,2069,2080,2092,2103,2115,2127,2139],{"type":26,"tag":87,"props":1636,"children":1637},{"class":89,"line":90},[1638,1643],{"type":26,"tag":87,"props":1639,"children":1640},{"style":230},[1641],{"type":39,"value":1642},"volumes",{"type":26,"tag":87,"props":1644,"children":1645},{"style":236},[1646],{"type":39,"value":239},{"type":26,"tag":87,"props":1648,"children":1649},{"class":89,"line":242},[1650,1655],{"type":26,"tag":87,"props":1651,"children":1652},{"style":230},[1653],{"type":39,"value":1654},"  nextcloud",{"type":26,"tag":87,"props":1656,"children":1657},{"style":236},[1658],{"type":39,"value":239},{"type":26,"tag":87,"props":1660,"children":1661},{"class":89,"line":256},[1662,1667],{"type":26,"tag":87,"props":1663,"children":1664},{"style":230},[1665],{"type":39,"value":1666},"  db",{"type":26,"tag":87,"props":1668,"children":1669},{"style":236},[1670],{"type":39,"value":239},{"type":26,"tag":87,"props":1672,"children":1673},{"class":89,"line":266},[1674],{"type":26,"tag":87,"props":1675,"children":1676},{"emptyLinePlaceholder":260},[1677],{"type":39,"value":263},{"type":26,"tag":87,"props":1679,"children":1680},{"class":89,"line":279},[1681,1686],{"type":26,"tag":87,"props":1682,"children":1683},{"style":230},[1684],{"type":39,"value":1685},"services",{"type":26,"tag":87,"props":1687,"children":1688},{"style":236},[1689],{"type":39,"value":239},{"type":26,"tag":87,"props":1691,"children":1692},{"class":89,"line":214},[1693,1697],{"type":26,"tag":87,"props":1694,"children":1695},{"style":230},[1696],{"type":39,"value":1666},{"type":26,"tag":87,"props":1698,"children":1699},{"style":236},[1700],{"type":39,"value":239},{"type":26,"tag":87,"props":1702,"children":1703},{"class":89,"line":312},[1704,1709,1713],{"type":26,"tag":87,"props":1705,"children":1706},{"style":230},[1707],{"type":39,"value":1708},"    image",{"type":26,"tag":87,"props":1710,"children":1711},{"style":236},[1712],{"type":39,"value":304},{"type":26,"tag":87,"props":1714,"children":1715},{"style":99},[1716],{"type":39,"value":1717},"mariadb:11.8\n",{"type":26,"tag":87,"props":1719,"children":1720},{"class":89,"line":336},[1721,1726,1730],{"type":26,"tag":87,"props":1722,"children":1723},{"style":230},[1724],{"type":39,"value":1725},"    restart",{"type":26,"tag":87,"props":1727,"children":1728},{"style":236},[1729],{"type":39,"value":304},{"type":26,"tag":87,"props":1731,"children":1732},{"style":99},[1733],{"type":39,"value":1734},"unless-stopped\n",{"type":26,"tag":87,"props":1736,"children":1737},{"class":89,"line":353},[1738,1743],{"type":26,"tag":87,"props":1739,"children":1740},{"style":230},[1741],{"type":39,"value":1742},"    volumes",{"type":26,"tag":87,"props":1744,"children":1745},{"style":236},[1746],{"type":39,"value":239},{"type":26,"tag":87,"props":1748,"children":1749},{"class":89,"line":366},[1750,1754],{"type":26,"tag":87,"props":1751,"children":1752},{"style":236},[1753],{"type":39,"value":872},{"type":26,"tag":87,"props":1755,"children":1756},{"style":99},[1757],{"type":39,"value":1758},"db:/var/lib/mysql\n",{"type":26,"tag":87,"props":1760,"children":1761},{"class":89,"line":384},[1762,1767],{"type":26,"tag":87,"props":1763,"children":1764},{"style":230},[1765],{"type":39,"value":1766},"    environment",{"type":26,"tag":87,"props":1768,"children":1769},{"style":236},[1770],{"type":39,"value":239},{"type":26,"tag":87,"props":1772,"children":1773},{"class":89,"line":402},[1774,1778],{"type":26,"tag":87,"props":1775,"children":1776},{"style":236},[1777],{"type":39,"value":872},{"type":26,"tag":87,"props":1779,"children":1780},{"style":99},[1781],{"type":39,"value":1782},"MARIADB_ROOT_PASSWORD=${NEXTCLOUD_MARIADB_ROOT_PASSWORD:?error}\n",{"type":26,"tag":87,"props":1784,"children":1785},{"class":89,"line":415},[1786,1790],{"type":26,"tag":87,"props":1787,"children":1788},{"style":236},[1789],{"type":39,"value":872},{"type":26,"tag":87,"props":1791,"children":1792},{"style":99},[1793],{"type":39,"value":1794},"MARIADB_PASSWORD=${NEXTCLOUD_MARIADB_PASSWORD:?error}\n",{"type":26,"tag":87,"props":1796,"children":1797},{"class":89,"line":215},[1798,1802],{"type":26,"tag":87,"props":1799,"children":1800},{"style":236},[1801],{"type":39,"value":872},{"type":26,"tag":87,"props":1803,"children":1804},{"style":99},[1805],{"type":39,"value":1806},"MARIADB_DATABASE=nextcloud\n",{"type":26,"tag":87,"props":1808,"children":1809},{"class":89,"line":216},[1810,1814],{"type":26,"tag":87,"props":1811,"children":1812},{"style":236},[1813],{"type":39,"value":872},{"type":26,"tag":87,"props":1815,"children":1816},{"style":99},[1817],{"type":39,"value":1818},"MARIADB_USER=nextcloud\n",{"type":26,"tag":87,"props":1820,"children":1821},{"class":89,"line":217},[1822,1827],{"type":26,"tag":87,"props":1823,"children":1824},{"style":230},[1825],{"type":39,"value":1826},"    command",{"type":26,"tag":87,"props":1828,"children":1829},{"style":236},[1830],{"type":39,"value":239},{"type":26,"tag":87,"props":1832,"children":1833},{"class":89,"line":218},[1834,1838],{"type":26,"tag":87,"props":1835,"children":1836},{"style":236},[1837],{"type":39,"value":872},{"type":26,"tag":87,"props":1839,"children":1840},{"style":99},[1841],{"type":39,"value":1842},"--transaction-isolation=READ-COMMITTED\n",{"type":26,"tag":87,"props":1844,"children":1845},{"class":89,"line":219},[1846,1850],{"type":26,"tag":87,"props":1847,"children":1848},{"style":236},[1849],{"type":39,"value":872},{"type":26,"tag":87,"props":1851,"children":1852},{"style":99},[1853],{"type":39,"value":1854},"--log-bin=binlog\n",{"type":26,"tag":87,"props":1856,"children":1857},{"class":89,"line":503},[1858,1862],{"type":26,"tag":87,"props":1859,"children":1860},{"style":236},[1861],{"type":39,"value":872},{"type":26,"tag":87,"props":1863,"children":1864},{"style":99},[1865],{"type":39,"value":1866},"--binlog-format=ROW\n",{"type":26,"tag":87,"props":1868,"children":1869},{"class":89,"line":516},[1870,1875],{"type":26,"tag":87,"props":1871,"children":1872},{"style":230},[1873],{"type":39,"value":1874},"    healthcheck",{"type":26,"tag":87,"props":1876,"children":1877},{"style":236},[1878],{"type":39,"value":239},{"type":26,"tag":87,"props":1880,"children":1881},{"class":89,"line":538},[1882,1887,1891,1896,1901,1906,1910,1915,1919,1924],{"type":26,"tag":87,"props":1883,"children":1884},{"style":230},[1885],{"type":39,"value":1886},"      test",{"type":26,"tag":87,"props":1888,"children":1889},{"style":236},[1890],{"type":39,"value":323},{"type":26,"tag":87,"props":1892,"children":1893},{"style":99},[1894],{"type":39,"value":1895},"\"CMD\"",{"type":26,"tag":87,"props":1897,"children":1898},{"style":236},[1899],{"type":39,"value":1900},", ",{"type":26,"tag":87,"props":1902,"children":1903},{"style":99},[1904],{"type":39,"value":1905},"\"healthcheck.sh\"",{"type":26,"tag":87,"props":1907,"children":1908},{"style":236},[1909],{"type":39,"value":1900},{"type":26,"tag":87,"props":1911,"children":1912},{"style":99},[1913],{"type":39,"value":1914},"\"--connect\"",{"type":26,"tag":87,"props":1916,"children":1917},{"style":236},[1918],{"type":39,"value":1900},{"type":26,"tag":87,"props":1920,"children":1921},{"style":99},[1922],{"type":39,"value":1923},"\"--innodb_initialized\"",{"type":26,"tag":87,"props":1925,"children":1926},{"style":236},[1927],{"type":39,"value":333},{"type":26,"tag":87,"props":1929,"children":1930},{"class":89,"line":556},[1931,1936,1940],{"type":26,"tag":87,"props":1932,"children":1933},{"style":230},[1934],{"type":39,"value":1935},"      interval",{"type":26,"tag":87,"props":1937,"children":1938},{"style":236},[1939],{"type":39,"value":304},{"type":26,"tag":87,"props":1941,"children":1942},{"style":99},[1943],{"type":39,"value":1944},"15s\n",{"type":26,"tag":87,"props":1946,"children":1947},{"class":89,"line":595},[1948,1953,1957],{"type":26,"tag":87,"props":1949,"children":1950},{"style":230},[1951],{"type":39,"value":1952},"      timeout",{"type":26,"tag":87,"props":1954,"children":1955},{"style":236},[1956],{"type":39,"value":304},{"type":26,"tag":87,"props":1958,"children":1959},{"style":99},[1960],{"type":39,"value":1961},"5s\n",{"type":26,"tag":87,"props":1963,"children":1964},{"class":89,"line":893},[1965,1970,1974],{"type":26,"tag":87,"props":1966,"children":1967},{"style":230},[1968],{"type":39,"value":1969},"      retries",{"type":26,"tag":87,"props":1971,"children":1972},{"style":236},[1973],{"type":39,"value":304},{"type":26,"tag":87,"props":1975,"children":1976},{"style":1060},[1977],{"type":39,"value":1978},"6\n",{"type":26,"tag":87,"props":1980,"children":1981},{"class":89,"line":905},[1982],{"type":26,"tag":87,"props":1983,"children":1984},{"emptyLinePlaceholder":260},[1985],{"type":39,"value":263},{"type":26,"tag":87,"props":1987,"children":1988},{"class":89,"line":925},[1989,1993],{"type":26,"tag":87,"props":1990,"children":1991},{"style":230},[1992],{"type":39,"value":1654},{"type":26,"tag":87,"props":1994,"children":1995},{"style":236},[1996],{"type":39,"value":239},{"type":26,"tag":87,"props":1998,"children":1999},{"class":89,"line":941},[2000,2004,2008],{"type":26,"tag":87,"props":2001,"children":2002},{"style":230},[2003],{"type":39,"value":1708},{"type":26,"tag":87,"props":2005,"children":2006},{"style":236},[2007],{"type":39,"value":304},{"type":26,"tag":87,"props":2009,"children":2010},{"style":99},[2011],{"type":39,"value":2012},"nextcloud:32.0.0\n",{"type":26,"tag":87,"props":2014,"children":2015},{"class":89,"line":961},[2016,2020,2024],{"type":26,"tag":87,"props":2017,"children":2018},{"style":230},[2019],{"type":39,"value":1725},{"type":26,"tag":87,"props":2021,"children":2022},{"style":236},[2023],{"type":39,"value":304},{"type":26,"tag":87,"props":2025,"children":2026},{"style":99},[2027],{"type":39,"value":1734},{"type":26,"tag":87,"props":2029,"children":2030},{"class":89,"line":969},[2031,2036],{"type":26,"tag":87,"props":2032,"children":2033},{"style":230},[2034],{"type":39,"value":2035},"    depends_on",{"type":26,"tag":87,"props":2037,"children":2038},{"style":236},[2039],{"type":39,"value":239},{"type":26,"tag":87,"props":2041,"children":2042},{"class":89,"line":982},[2043,2048],{"type":26,"tag":87,"props":2044,"children":2045},{"style":230},[2046],{"type":39,"value":2047},"      db",{"type":26,"tag":87,"props":2049,"children":2050},{"style":236},[2051],{"type":39,"value":239},{"type":26,"tag":87,"props":2053,"children":2054},{"class":89,"line":998},[2055,2060,2064],{"type":26,"tag":87,"props":2056,"children":2057},{"style":230},[2058],{"type":39,"value":2059},"        condition",{"type":26,"tag":87,"props":2061,"children":2062},{"style":236},[2063],{"type":39,"value":304},{"type":26,"tag":87,"props":2065,"children":2066},{"style":99},[2067],{"type":39,"value":2068},"service_healthy\n",{"type":26,"tag":87,"props":2070,"children":2071},{"class":89,"line":1010},[2072,2076],{"type":26,"tag":87,"props":2073,"children":2074},{"style":230},[2075],{"type":39,"value":1742},{"type":26,"tag":87,"props":2077,"children":2078},{"style":236},[2079],{"type":39,"value":239},{"type":26,"tag":87,"props":2081,"children":2082},{"class":89,"line":1027},[2083,2087],{"type":26,"tag":87,"props":2084,"children":2085},{"style":236},[2086],{"type":39,"value":872},{"type":26,"tag":87,"props":2088,"children":2089},{"style":99},[2090],{"type":39,"value":2091},"nextcloud:/var/www/html\n",{"type":26,"tag":87,"props":2093,"children":2094},{"class":89,"line":1047},[2095,2099],{"type":26,"tag":87,"props":2096,"children":2097},{"style":230},[2098],{"type":39,"value":1766},{"type":26,"tag":87,"props":2100,"children":2101},{"style":236},[2102],{"type":39,"value":239},{"type":26,"tag":87,"props":2104,"children":2105},{"class":89,"line":1066},[2106,2110],{"type":26,"tag":87,"props":2107,"children":2108},{"style":236},[2109],{"type":39,"value":872},{"type":26,"tag":87,"props":2111,"children":2112},{"style":99},[2113],{"type":39,"value":2114},"MYSQL_PASSWORD=${NEXTCLOUD_MARIADB_PASSWORD:?error}\n",{"type":26,"tag":87,"props":2116,"children":2117},{"class":89,"line":1078},[2118,2122],{"type":26,"tag":87,"props":2119,"children":2120},{"style":236},[2121],{"type":39,"value":872},{"type":26,"tag":87,"props":2123,"children":2124},{"style":99},[2125],{"type":39,"value":2126},"MYSQL_DATABASE=nextcloud\n",{"type":26,"tag":87,"props":2128,"children":2129},{"class":89,"line":1091},[2130,2134],{"type":26,"tag":87,"props":2131,"children":2132},{"style":236},[2133],{"type":39,"value":872},{"type":26,"tag":87,"props":2135,"children":2136},{"style":99},[2137],{"type":39,"value":2138},"MYSQL_USER=nextcloud\n",{"type":26,"tag":87,"props":2140,"children":2141},{"class":89,"line":1103},[2142,2146],{"type":26,"tag":87,"props":2143,"children":2144},{"style":236},[2145],{"type":39,"value":872},{"type":26,"tag":87,"props":2147,"children":2148},{"style":99},[2149],{"type":39,"value":2150},"MYSQL_HOST=db\n",{"type":26,"tag":76,"props":2152,"children":2156},{"className":2153,"code":2154,"language":2155,"meta":7,"style":7},"language-dotenv shiki shiki-themes github-dark github-dark monokai","NEXTCLOUD_MARIADB_ROOT_PASSWORD=\nNEXTCLOUD_MARIADB_PASSWORD=\n","dotenv",[2157],{"type":26,"tag":83,"props":2158,"children":2159},{"__ignoreMap":7},[2160,2175],{"type":26,"tag":87,"props":2161,"children":2162},{"class":89,"line":90},[2163,2169],{"type":26,"tag":87,"props":2164,"children":2166},{"style":2165},"--shiki-default:#FFAB70;--shiki-dark:#FFAB70;--shiki-sepia:#F8F8F2",[2167],{"type":39,"value":2168},"NEXTCLOUD_MARIADB_ROOT_PASSWORD",{"type":26,"tag":87,"props":2170,"children":2172},{"style":2171},"--shiki-default:#F97583;--shiki-dark:#F97583;--shiki-sepia:#F92672",[2173],{"type":39,"value":2174},"=\n",{"type":26,"tag":87,"props":2176,"children":2177},{"class":89,"line":242},[2178,2183],{"type":26,"tag":87,"props":2179,"children":2180},{"style":2165},[2181],{"type":39,"value":2182},"NEXTCLOUD_MARIADB_PASSWORD",{"type":26,"tag":87,"props":2184,"children":2185},{"style":2171},[2186],{"type":39,"value":2174},{"type":26,"tag":35,"props":2188,"children":2189},{},[2190,2192,2198],{"type":39,"value":2191},"Werden als ",{"type":26,"tag":42,"props":2193,"children":2195},{"href":2194},"https://docs.gitlab.com/ci/variables/",[2196],{"type":39,"value":2197},"CI/CD-Variablen",{"type":39,"value":2199}," gespeichert.",{"type":26,"tag":2201,"props":2202,"children":2203},"hr",{},[],{"type":26,"tag":35,"props":2205,"children":2206},{},[2207],{"type":39,"value":2208},"Um den Stack zu deployen, haben wir folgende Pipeline:",{"type":26,"tag":76,"props":2210,"children":2213},{"className":210,"code":2211,"filename":2212,"language":220,"meta":7,"style":7},"stages:\n  - deploy\n\ndeploy:\n  stage: deploy\n  image: docker:28\n  variables:\n    DOCKER_HOST: ssh://[username@]\u003CIP or host>[:port]\n  script:\n    - for file in $(find . -type f -name docker-compose.yml); do docker compose -f $file up --remove-orphans --wait; done\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n\n",".gitlab-ci.yml",[2214],{"type":26,"tag":83,"props":2215,"children":2216},{"__ignoreMap":7},[2217,2228,2240,2247,2259,2274,2290,2301,2318,2329,2341,2352],{"type":26,"tag":87,"props":2218,"children":2219},{"class":89,"line":90},[2220,2224],{"type":26,"tag":87,"props":2221,"children":2222},{"style":230},[2223],{"type":39,"value":233},{"type":26,"tag":87,"props":2225,"children":2226},{"style":236},[2227],{"type":39,"value":239},{"type":26,"tag":87,"props":2229,"children":2230},{"class":89,"line":242},[2231,2235],{"type":26,"tag":87,"props":2232,"children":2233},{"style":236},[2234],{"type":39,"value":248},{"type":26,"tag":87,"props":2236,"children":2237},{"style":99},[2238],{"type":39,"value":2239},"deploy\n",{"type":26,"tag":87,"props":2241,"children":2242},{"class":89,"line":256},[2243],{"type":26,"tag":87,"props":2244,"children":2245},{"emptyLinePlaceholder":260},[2246],{"type":39,"value":263},{"type":26,"tag":87,"props":2248,"children":2249},{"class":89,"line":266},[2250,2255],{"type":26,"tag":87,"props":2251,"children":2252},{"style":230},[2253],{"type":39,"value":2254},"deploy",{"type":26,"tag":87,"props":2256,"children":2257},{"style":236},[2258],{"type":39,"value":239},{"type":26,"tag":87,"props":2260,"children":2261},{"class":89,"line":279},[2262,2266,2270],{"type":26,"tag":87,"props":2263,"children":2264},{"style":230},[2265],{"type":39,"value":342},{"type":26,"tag":87,"props":2267,"children":2268},{"style":236},[2269],{"type":39,"value":304},{"type":26,"tag":87,"props":2271,"children":2272},{"style":99},[2273],{"type":39,"value":2239},{"type":26,"tag":87,"props":2275,"children":2276},{"class":89,"line":214},[2277,2281,2285],{"type":26,"tag":87,"props":2278,"children":2279},{"style":230},[2280],{"type":39,"value":285},{"type":26,"tag":87,"props":2282,"children":2283},{"style":236},[2284],{"type":39,"value":304},{"type":26,"tag":87,"props":2286,"children":2287},{"style":99},[2288],{"type":39,"value":2289},"docker:28\n",{"type":26,"tag":87,"props":2291,"children":2292},{"class":89,"line":312},[2293,2297],{"type":26,"tag":87,"props":2294,"children":2295},{"style":230},[2296],{"type":39,"value":359},{"type":26,"tag":87,"props":2298,"children":2299},{"style":236},[2300],{"type":39,"value":239},{"type":26,"tag":87,"props":2302,"children":2303},{"class":89,"line":336},[2304,2309,2313],{"type":26,"tag":87,"props":2305,"children":2306},{"style":230},[2307],{"type":39,"value":2308},"    DOCKER_HOST",{"type":26,"tag":87,"props":2310,"children":2311},{"style":236},[2312],{"type":39,"value":304},{"type":26,"tag":87,"props":2314,"children":2315},{"style":99},[2316],{"type":39,"value":2317},"ssh://[username@]\u003CIP or host>[:port]\n",{"type":26,"tag":87,"props":2319,"children":2320},{"class":89,"line":353},[2321,2325],{"type":26,"tag":87,"props":2322,"children":2323},{"style":230},[2324],{"type":39,"value":408},{"type":26,"tag":87,"props":2326,"children":2327},{"style":236},[2328],{"type":39,"value":239},{"type":26,"tag":87,"props":2330,"children":2331},{"class":89,"line":366},[2332,2336],{"type":26,"tag":87,"props":2333,"children":2334},{"style":236},[2335],{"type":39,"value":421},{"type":26,"tag":87,"props":2337,"children":2338},{"style":99},[2339],{"type":39,"value":2340},"for file in $(find . -type f -name docker-compose.yml); do docker compose -f $file up --remove-orphans --wait; done\n",{"type":26,"tag":87,"props":2342,"children":2343},{"class":89,"line":384},[2344,2348],{"type":26,"tag":87,"props":2345,"children":2346},{"style":230},[2347],{"type":39,"value":509},{"type":26,"tag":87,"props":2349,"children":2350},{"style":236},[2351],{"type":39,"value":239},{"type":26,"tag":87,"props":2353,"children":2354},{"class":89,"line":402},[2355,2359,2363,2367],{"type":26,"tag":87,"props":2356,"children":2357},{"style":236},[2358],{"type":39,"value":421},{"type":26,"tag":87,"props":2360,"children":2361},{"style":230},[2362],{"type":39,"value":526},{"type":26,"tag":87,"props":2364,"children":2365},{"style":236},[2366],{"type":39,"value":304},{"type":26,"tag":87,"props":2368,"children":2369},{"style":99},[2370],{"type":39,"value":2371},"$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n",{"type":26,"tag":35,"props":2373,"children":2374},{},[2375,2377,2383],{"type":39,"value":2376},"Die Pipeline läuft bei jedem Commit auf dem Standard-Branch, iteriert über alle ",{"type":26,"tag":83,"props":2378,"children":2380},{"className":2379},[],[2381],{"type":39,"value":2382},"docker-compose.yml",{"type":39,"value":2384},"-Dateien und deployt sie.",{"type":26,"tag":64,"props":2386,"children":2388},{"id":2387},"halte-deine-software-aktuell-mit-renovate-bot",[2389],{"type":39,"value":2390},"Halte deine Software aktuell mit Renovate-Bot",{"type":26,"tag":35,"props":2392,"children":2393},{},[2394],{"type":39,"value":2395},"Hier kommt Renovate ins Spiel.",{"type":26,"tag":76,"props":2397,"children":2401},{"className":2398,"code":2399,"filename":2400,"language":1327,"meta":7,"style":7},"language-json shiki shiki-themes github-dark github-dark monokai","{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"config:best-practices\"\n  ]\n}\n","renovate.json",[2402],{"type":26,"tag":83,"props":2403,"children":2404},{"__ignoreMap":7},[2405,2413,2437,2450,2458,2466],{"type":26,"tag":87,"props":2406,"children":2407},{"class":89,"line":90},[2408],{"type":26,"tag":87,"props":2409,"children":2410},{"style":236},[2411],{"type":39,"value":2412},"{\n",{"type":26,"tag":87,"props":2414,"children":2415},{"class":89,"line":242},[2416,2422,2426,2432],{"type":26,"tag":87,"props":2417,"children":2419},{"style":2418},"--shiki-default:#79B8FF;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic",[2420],{"type":39,"value":2421},"  \"$schema\"",{"type":26,"tag":87,"props":2423,"children":2424},{"style":236},[2425],{"type":39,"value":304},{"type":26,"tag":87,"props":2427,"children":2429},{"style":2428},"--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF;--shiki-sepia:#CFCFC2",[2430],{"type":39,"value":2431},"\"https://docs.renovatebot.com/renovate-schema.json\"",{"type":26,"tag":87,"props":2433,"children":2434},{"style":236},[2435],{"type":39,"value":2436},",\n",{"type":26,"tag":87,"props":2438,"children":2439},{"class":89,"line":256},[2440,2445],{"type":26,"tag":87,"props":2441,"children":2442},{"style":2418},[2443],{"type":39,"value":2444},"  \"extends\"",{"type":26,"tag":87,"props":2446,"children":2447},{"style":236},[2448],{"type":39,"value":2449},": [\n",{"type":26,"tag":87,"props":2451,"children":2452},{"class":89,"line":266},[2453],{"type":26,"tag":87,"props":2454,"children":2455},{"style":2428},[2456],{"type":39,"value":2457},"    \"config:best-practices\"\n",{"type":26,"tag":87,"props":2459,"children":2460},{"class":89,"line":279},[2461],{"type":26,"tag":87,"props":2462,"children":2463},{"style":236},[2464],{"type":39,"value":2465},"  ]\n",{"type":26,"tag":87,"props":2467,"children":2468},{"class":89,"line":214},[2469],{"type":26,"tag":87,"props":2470,"children":2471},{"style":236},[2472],{"type":39,"value":2473},"}\n",{"type":26,"tag":35,"props":2475,"children":2476},{},[2477],{"type":39,"value":2478},"Renovate erstellt für jedes Update einen Merge-Request. Super!",{"type":26,"tag":64,"props":2480,"children":2482},{"id":2481},"automatisierte-sicherheitsupdates-und-opt-in-für-minor-major-versionen",[2483],{"type":39,"value":2484},"Automatisierte Sicherheitsupdates und Opt-in für Minor-/Major-Versionen",{"type":26,"tag":35,"props":2486,"children":2487},{},[2488],{"type":39,"value":2489},"Die aktuelle Konfiguration erstellt für jedes Update einen Merge-Request, aber wir möchten, dass Sicherheitsupdates ohne Benutzerinteraktion erfolgen.",{"type":26,"tag":35,"props":2491,"children":2492},{},[2493,2495,2501],{"type":39,"value":2494},"Es ist wichtig zu verstehen, wie Docker-Images versioniert bzw. getaggt werden. Es hängt vom jeweiligen Image ab, aber nehmen wir die offizielle ",{"type":26,"tag":42,"props":2496,"children":2498},{"href":2497},"https://hub.docker.com/_/mariadb",[2499],{"type":39,"value":2500},"MariaDB",{"type":39,"value":2502}," als Beispiel.",{"type":26,"tag":35,"props":2504,"children":2505},{},[2506,2508,2514],{"type":39,"value":2507},"Es gibt ",{"type":26,"tag":83,"props":2509,"children":2511},{"className":2510},[],[2512],{"type":39,"value":2513},"11.8.3-noble, 11.8-noble, 11-noble, lts-noble, 11.8.3, 11.8, 11, lts",{"type":39,"value":2515},", die alle auf dasselbe Image verweisen.",{"type":26,"tag":35,"props":2517,"children":2518},{},[2519,2525,2527,2533,2535,2541,2542,2548],{"type":26,"tag":83,"props":2520,"children":2522},{"className":2521},[],[2523],{"type":39,"value":2524},"11.8.3-noble",{"type":39,"value":2526}," bedeutet, dass wir MariaDB in Version ",{"type":26,"tag":83,"props":2528,"children":2530},{"className":2529},[],[2531],{"type":39,"value":2532},"11.8.3",{"type":39,"value":2534}," auf Basis von Ubuntu Noble erhalten.\n",{"type":26,"tag":83,"props":2536,"children":2538},{"className":2537},[],[2539],{"type":39,"value":2540},"11.8-noble",{"type":39,"value":2526},{"type":26,"tag":83,"props":2543,"children":2545},{"className":2544},[],[2546],{"type":39,"value":2547},"11.8.\u003Clatest_patch>",{"type":39,"value":2549}," auf Basis von Ubuntu Noble erhalten.",{"type":26,"tag":35,"props":2551,"children":2552},{},[2553,2555,2561,2563,2568,2570,2575],{"type":39,"value":2554},"Wenn eine neue Version von MariaDB veröffentlicht wird, z. B. ",{"type":26,"tag":83,"props":2556,"children":2558},{"className":2557},[],[2559],{"type":39,"value":2560},"11.8.4-noble",{"type":39,"value":2562},", wird ein neuer Tag ",{"type":26,"tag":83,"props":2564,"children":2566},{"className":2565},[],[2567],{"type":39,"value":2560},{"type":39,"value":2569}," veröffentlicht, aber der Tag ",{"type":26,"tag":83,"props":2571,"children":2573},{"className":2572},[],[2574],{"type":39,"value":2540},{"type":39,"value":2576}," wird aktualisiert.",{"type":26,"tag":35,"props":2578,"children":2579},{},[2580,2582,2587],{"type":39,"value":2581},"Gleiches gilt für das Ubuntu-Update. Der Tag ",{"type":26,"tag":83,"props":2583,"children":2585},{"className":2584},[],[2586],{"type":39,"value":2524},{"type":39,"value":2588}," kann aktualisiert werden, wenn das Image mit dem neuesten Ubuntu-Image erneut gebaut wird.",{"type":26,"tag":35,"props":2590,"children":2591},{},[2592,2598,2600,2606],{"type":26,"tag":83,"props":2593,"children":2595},{"className":2594},[],[2596],{"type":39,"value":2597},"docker compose up",{"type":39,"value":2599}," mit ",{"type":26,"tag":83,"props":2601,"children":2603},{"className":2602},[],[2604],{"type":39,"value":2605},"mariadb:11.8-noble",{"type":39,"value":2607}," wird nichts bewirken, weil Docker sich dieser Änderung nicht bewusst ist.",{"type":26,"tag":35,"props":2609,"children":2610},{},[2611,2613,2619],{"type":39,"value":2612},"Im Beispiel oben verweisen wir auf ",{"type":26,"tag":83,"props":2614,"children":2616},{"className":2615},[],[2617],{"type":39,"value":2618},"mariadb:11.8",{"type":39,"value":2620},", weil wir die neueste Patch-Version auf Basis des neuesten Betriebssystems verwenden möchten.",{"type":26,"tag":2201,"props":2622,"children":2623},{},[],{"type":26,"tag":35,"props":2625,"children":2626},{},[2627],{"type":39,"value":2628},"Wie soll Docker mitgeteilt werden, dass es eine neue Version gibt?",{"type":26,"tag":35,"props":2630,"children":2631},{},[2632,2634,2640],{"type":39,"value":2633},"Die Hauptidee ist, das Docker-Image zusätzlich mit einem ",{"type":26,"tag":42,"props":2635,"children":2637},{"href":2636},"https://docs.docker.com/dhi/core-concepts/digests/",[2638],{"type":39,"value":2639},"Digest",{"type":39,"value":2641}," anzugeben.",{"type":26,"tag":35,"props":2643,"children":2644},{},[2645,2647,2652,2654,2660],{"type":39,"value":2646},"Wenn Renovate das erste Mal läuft, findet es den Verweis auf ",{"type":26,"tag":83,"props":2648,"children":2650},{"className":2649},[],[2651],{"type":39,"value":2618},{"type":39,"value":2653}," und erstellt einen Merge-Request, um den Digest auf so etwas wie ",{"type":26,"tag":83,"props":2655,"children":2657},{"className":2656},[],[2658],{"type":39,"value":2659},"mariadb:11.8@sha256:ae6119716edac6998ae85508431b3d2e666530ddf4e94c61a10710caec9b0f71",{"type":39,"value":2661}," festzulegen.",{"type":26,"tag":35,"props":2663,"children":2664},{},[2665],{"type":39,"value":2666},"Es überwacht das auch, sodass bei jedem Update des Images der Digest wechselt und Renovate einen Merge-Request erstellt.",{"type":26,"tag":35,"props":2668,"children":2669},{},[2670],{"type":39,"value":2671},"Damit diese Updates automatisch gemergt werden, müssen wir ein paar Anpassungen vornehmen.",{"type":26,"tag":76,"props":2673,"children":2676},{"className":2398,"code":2674,"filename":2400,"highlights":2675,"language":1327,"meta":7,"style":7},"{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"config:best-practices\",\n    \"default:automergeDigest\"\n  ],\n  \"automergeType\": \"branch\",\n  \"ignoreTests\": true\n}\n",[279,214,312,336],[2677],{"type":26,"tag":83,"props":2678,"children":2679},{"__ignoreMap":7},[2680,2687,2706,2717,2729,2738,2747,2769,2786],{"type":26,"tag":87,"props":2681,"children":2682},{"class":89,"line":90},[2683],{"type":26,"tag":87,"props":2684,"children":2685},{"style":236},[2686],{"type":39,"value":2412},{"type":26,"tag":87,"props":2688,"children":2689},{"class":89,"line":242},[2690,2694,2698,2702],{"type":26,"tag":87,"props":2691,"children":2692},{"style":2418},[2693],{"type":39,"value":2421},{"type":26,"tag":87,"props":2695,"children":2696},{"style":236},[2697],{"type":39,"value":304},{"type":26,"tag":87,"props":2699,"children":2700},{"style":2428},[2701],{"type":39,"value":2431},{"type":26,"tag":87,"props":2703,"children":2704},{"style":236},[2705],{"type":39,"value":2436},{"type":26,"tag":87,"props":2707,"children":2708},{"class":89,"line":256},[2709,2713],{"type":26,"tag":87,"props":2710,"children":2711},{"style":2418},[2712],{"type":39,"value":2444},{"type":26,"tag":87,"props":2714,"children":2715},{"style":236},[2716],{"type":39,"value":2449},{"type":26,"tag":87,"props":2718,"children":2719},{"class":89,"line":266},[2720,2725],{"type":26,"tag":87,"props":2721,"children":2722},{"style":2428},[2723],{"type":39,"value":2724},"    \"config:best-practices\"",{"type":26,"tag":87,"props":2726,"children":2727},{"style":236},[2728],{"type":39,"value":2436},{"type":26,"tag":87,"props":2730,"children":2732},{"class":2731,"line":279},[89,293],[2733],{"type":26,"tag":87,"props":2734,"children":2735},{"style":2428},[2736],{"type":39,"value":2737},"    \"default:automergeDigest\"\n",{"type":26,"tag":87,"props":2739,"children":2741},{"class":2740,"line":214},[89,293],[2742],{"type":26,"tag":87,"props":2743,"children":2744},{"style":236},[2745],{"type":39,"value":2746},"  ],\n",{"type":26,"tag":87,"props":2748,"children":2750},{"class":2749,"line":312},[89,293],[2751,2756,2760,2765],{"type":26,"tag":87,"props":2752,"children":2753},{"style":2418},[2754],{"type":39,"value":2755},"  \"automergeType\"",{"type":26,"tag":87,"props":2757,"children":2758},{"style":236},[2759],{"type":39,"value":304},{"type":26,"tag":87,"props":2761,"children":2762},{"style":2428},[2763],{"type":39,"value":2764},"\"branch\"",{"type":26,"tag":87,"props":2766,"children":2767},{"style":236},[2768],{"type":39,"value":2436},{"type":26,"tag":87,"props":2770,"children":2772},{"class":2771,"line":336},[89,293],[2773,2778,2782],{"type":26,"tag":87,"props":2774,"children":2775},{"style":2418},[2776],{"type":39,"value":2777},"  \"ignoreTests\"",{"type":26,"tag":87,"props":2779,"children":2780},{"style":236},[2781],{"type":39,"value":304},{"type":26,"tag":87,"props":2783,"children":2784},{"style":1060},[2785],{"type":39,"value":1063},{"type":26,"tag":87,"props":2787,"children":2788},{"class":89,"line":353},[2789],{"type":26,"tag":87,"props":2790,"children":2791},{"style":236},[2792],{"type":39,"value":2473},{"type":26,"tag":35,"props":2794,"children":2795},{},[2796,2798,2804,2805,2811],{"type":39,"value":2797},"Das weist Renovate an, die Digest-Updates automatisch zu mergen, ohne einen Merge-Request zu erstellen. Das reduziert das \"Rauschen\", weil es keine Merge-Request-Benachrichtigung gibt.\nMehr dazu findest du unter ",{"type":26,"tag":42,"props":2799,"children":2801},{"href":2800},"https://docs.renovatebot.com/key-concepts/automerge/#branch-vs-pr-automerging",[2802],{"type":39,"value":2803},"automergeType",{"type":39,"value":1397},{"type":26,"tag":42,"props":2806,"children":2808},{"href":2807},"https://docs.renovatebot.com/key-concepts/automerge/#absence-of-tests",[2809],{"type":39,"value":2810},"ignoreTests",{"type":39,"value":155},{"type":26,"tag":1192,"props":2813,"children":2814},{},[2815],{"type":39,"value":1196},{"title":7,"searchDepth":242,"depth":242,"links":2817},[2818,2819,2820,2821,2822],{"id":1429,"depth":242,"text":1432},{"id":1466,"depth":242,"text":1469},{"id":1505,"depth":242,"text":1508},{"id":2387,"depth":242,"text":2390},{"id":2481,"depth":242,"text":2484},{"_path":1219,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1220,"description":1221,"author":10,"image":11,"releaseDate":1222,"blogCategories":2824,"articleTags":2825,"tags":2826,"body":2827,"_type":1201,"_id":1226,"_source":1203,"_file":1227,"_stem":1228,"_extension":1206},[14,15],[15],[21],{"type":23,"children":2828,"toc":3976},[2829,2840,2845,2970,2975,3048,3054,3079,3084,3112,3125,3143,3149,3166,3267,3272,3277,3302,3348,3351,3356,3696,3701,3737,3744,3752,3805,3809,3816,3844,3850,3855,3861,3866,3878,3886,3892,3904,3972],{"type":26,"tag":35,"props":2830,"children":2831},{},[2832,2838],{"type":26,"tag":42,"props":2833,"children":2835},{"href":2834},"https://doc.traefik.io/traefik/",[2836],{"type":39,"value":2837},"Traefik",{"type":39,"value":2839}," ist ein Reverse Proxy mit exzellenter Docker-Integration. Er verwendet Labels, die an Containern angebracht sind, um den Datenverkehr zu ihnen zu leiten.",{"type":26,"tag":35,"props":2841,"children":2842},{},[2843],{"type":39,"value":2844},"Ein typisches Set an Labels sieht ungefähr so aus:",{"type":26,"tag":76,"props":2846,"children":2850},{"code":2847,"filename":2848,"highlights":2849,"language":220,"meta":7,"className":210,"style":7},"services:\n  whoami:\n    image: traefik/whoami\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.whoami.rule=Host(`whoami.example.com`)\"\n      - \"traefik.http.routers.whoami.entrypoints=websecure\"\n      - \"traefik.http.routers.whoami.tls=true\"\n      - \"traefik.http.routers.whoami.tls.certresolver=letsencrypt\"\n","whoami/docker-compose.yaml",[279,214,312,336,353],[2851],{"type":26,"tag":83,"props":2852,"children":2853},{"__ignoreMap":7},[2854,2865,2877,2893,2905,2918,2931,2944,2957],{"type":26,"tag":87,"props":2855,"children":2856},{"class":89,"line":90},[2857,2861],{"type":26,"tag":87,"props":2858,"children":2859},{"style":230},[2860],{"type":39,"value":1685},{"type":26,"tag":87,"props":2862,"children":2863},{"style":236},[2864],{"type":39,"value":239},{"type":26,"tag":87,"props":2866,"children":2867},{"class":89,"line":242},[2868,2873],{"type":26,"tag":87,"props":2869,"children":2870},{"style":230},[2871],{"type":39,"value":2872},"  whoami",{"type":26,"tag":87,"props":2874,"children":2875},{"style":236},[2876],{"type":39,"value":239},{"type":26,"tag":87,"props":2878,"children":2879},{"class":89,"line":256},[2880,2884,2888],{"type":26,"tag":87,"props":2881,"children":2882},{"style":230},[2883],{"type":39,"value":1708},{"type":26,"tag":87,"props":2885,"children":2886},{"style":236},[2887],{"type":39,"value":304},{"type":26,"tag":87,"props":2889,"children":2890},{"style":99},[2891],{"type":39,"value":2892},"traefik/whoami\n",{"type":26,"tag":87,"props":2894,"children":2895},{"class":89,"line":266},[2896,2901],{"type":26,"tag":87,"props":2897,"children":2898},{"style":230},[2899],{"type":39,"value":2900},"    labels",{"type":26,"tag":87,"props":2902,"children":2903},{"style":236},[2904],{"type":39,"value":239},{"type":26,"tag":87,"props":2906,"children":2908},{"class":2907,"line":279},[89,293],[2909,2913],{"type":26,"tag":87,"props":2910,"children":2911},{"style":236},[2912],{"type":39,"value":872},{"type":26,"tag":87,"props":2914,"children":2915},{"style":99},[2916],{"type":39,"value":2917},"\"traefik.enable=true\"\n",{"type":26,"tag":87,"props":2919,"children":2921},{"class":2920,"line":214},[89,293],[2922,2926],{"type":26,"tag":87,"props":2923,"children":2924},{"style":236},[2925],{"type":39,"value":872},{"type":26,"tag":87,"props":2927,"children":2928},{"style":99},[2929],{"type":39,"value":2930},"\"traefik.http.routers.whoami.rule=Host(`whoami.example.com`)\"\n",{"type":26,"tag":87,"props":2932,"children":2934},{"class":2933,"line":312},[89,293],[2935,2939],{"type":26,"tag":87,"props":2936,"children":2937},{"style":236},[2938],{"type":39,"value":872},{"type":26,"tag":87,"props":2940,"children":2941},{"style":99},[2942],{"type":39,"value":2943},"\"traefik.http.routers.whoami.entrypoints=websecure\"\n",{"type":26,"tag":87,"props":2945,"children":2947},{"class":2946,"line":336},[89,293],[2948,2952],{"type":26,"tag":87,"props":2949,"children":2950},{"style":236},[2951],{"type":39,"value":872},{"type":26,"tag":87,"props":2953,"children":2954},{"style":99},[2955],{"type":39,"value":2956},"\"traefik.http.routers.whoami.tls=true\"\n",{"type":26,"tag":87,"props":2958,"children":2960},{"class":2959,"line":353},[89,293],[2961,2965],{"type":26,"tag":87,"props":2962,"children":2963},{"style":236},[2964],{"type":39,"value":872},{"type":26,"tag":87,"props":2966,"children":2967},{"style":99},[2968],{"type":39,"value":2969},"\"traefik.http.routers.whoami.tls.certresolver=letsencrypt\"\n",{"type":26,"tag":35,"props":2971,"children":2972},{},[2973],{"type":39,"value":2974},"In diesem Beispiel:",{"type":26,"tag":124,"props":2976,"children":2977},{},[2978,2989,3005,3010,3022,3027],{"type":26,"tag":128,"props":2979,"children":2980},{},[2981,2987],{"type":26,"tag":83,"props":2982,"children":2984},{"className":2983},[],[2985],{"type":39,"value":2986},"whoami",{"type":39,"value":2988}," ist der Name des \"Haupt\"-Dienstes (2)",{"type":26,"tag":128,"props":2990,"children":2991},{},[2992,2997,2999],{"type":26,"tag":83,"props":2993,"children":2995},{"className":2994},[],[2996],{"type":39,"value":2986},{"type":39,"value":2998}," ist auch der Standard-",{"type":26,"tag":42,"props":3000,"children":3002},{"href":3001},"https://docs.docker.com/compose/how-tos/project-name/",[3003],{"type":39,"value":3004},"Name des Compose-Projekts",{"type":26,"tag":128,"props":3006,"children":3007},{},[3008],{"type":39,"value":3009},"Traefik wird aktiviert (5)",{"type":26,"tag":128,"props":3011,"children":3012},{},[3013,3015,3020],{"type":39,"value":3014},"Der Dienst wird unter der Subdomain ",{"type":26,"tag":83,"props":3016,"children":3018},{"className":3017},[],[3019],{"type":39,"value":2986},{"type":39,"value":3021}," bereitgestellt (6)",{"type":26,"tag":128,"props":3023,"children":3024},{},[3025],{"type":39,"value":3026},"Die Auslieferung erfolgt über HTTPS (7)",{"type":26,"tag":128,"props":3028,"children":3029},{},[3030,3032,3038,3040,3046],{"type":39,"value":3031},"Ein vorkonfigurierter Certresolver namens ",{"type":26,"tag":83,"props":3033,"children":3035},{"className":3034},[],[3036],{"type":39,"value":3037},"letsencrypt",{"type":39,"value":3039}," wird für ",{"type":26,"tag":83,"props":3041,"children":3043},{"className":3042},[],[3044],{"type":39,"value":3045},"tls",{"type":39,"value":3047}," verwendet (8-9)",{"type":26,"tag":64,"props":3049,"children":3051},{"id":3050},"das-problem",[3052],{"type":39,"value":3053},"Das Problem",{"type":26,"tag":35,"props":3055,"children":3056},{},[3057,3058,3063,3065,3071,3073,3077],{"type":39,"value":40},{"type":26,"tag":42,"props":3059,"children":3060},{"href":1208},[3061],{"type":39,"value":3062},"anderen Beitrag über GitOps mit Docker",{"type":39,"value":3064}," habe ich das Konzept eingeführt,\n",{"type":26,"tag":83,"props":3066,"children":3068},{"className":3067},[],[3069],{"type":39,"value":3070},"git",{"type":39,"value":3072}," als „Source of Truth“ für Docker-Deployments mittels ",{"type":26,"tag":42,"props":3074,"children":3075},{"href":1400},[3076],{"type":39,"value":1403},{"type":39,"value":3078}," zu nutzen.",{"type":26,"tag":35,"props":3080,"children":3081},{},[3082],{"type":39,"value":3083},"Dabei gibt es einige Anforderungen:",{"type":26,"tag":124,"props":3085,"children":3086},{},[3087,3100],{"type":26,"tag":128,"props":3088,"children":3089},{},[3090,3092,3098],{"type":39,"value":3091},"Jeder Stack ist unter ",{"type":26,"tag":83,"props":3093,"children":3095},{"className":3094},[],[3096],{"type":39,"value":3097},"\u003Cstack_name>.\u003Cyour_domain>",{"type":39,"value":3099}," erreichbar",{"type":26,"tag":128,"props":3101,"children":3102},{},[3103,3105,3110],{"type":39,"value":3104},"Jeder Stack ist mit ",{"type":26,"tag":83,"props":3106,"children":3108},{"className":3107},[],[3109],{"type":39,"value":3045},{"type":39,"value":3111}," geschützt",{"type":26,"tag":35,"props":3113,"children":3114},{},[3115,3117,3123],{"type":39,"value":3116},"Wir könnten zwar in jeder ",{"type":26,"tag":83,"props":3118,"children":3120},{"className":3119},[],[3121],{"type":39,"value":3122},"docker-compose.yaml",{"type":39,"value":3124}," die Labels manuell hinzufügen, doch dabei zeigt sich schnell,\ndass wir die Konfiguration redundant wiederholen.",{"type":26,"tag":1173,"props":3126,"children":3127},{},[3128,3133,3138],{"type":26,"tag":128,"props":3129,"children":3130},{},[3131],{"type":39,"value":3132},"Traefik aktivieren",{"type":26,"tag":128,"props":3134,"children":3135},{},[3136],{"type":39,"value":3137},"Eine Subdomain zuweisen",{"type":26,"tag":128,"props":3139,"children":3140},{},[3141],{"type":39,"value":3142},"HTTPS aktivieren",{"type":26,"tag":64,"props":3144,"children":3146},{"id":3145},"die-lösung",[3147],{"type":39,"value":3148},"Die Lösung",{"type":26,"tag":35,"props":3150,"children":3151},{},[3152,3154,3164],{"type":39,"value":3153},"Mit hilfe der ",{"type":26,"tag":42,"props":3155,"children":3157},{"href":3156},"https://docs.docker.com/compose/how-tos/environment-variables/envvars/#compose_project_name",[3158],{"type":26,"tag":83,"props":3159,"children":3161},{"className":3160},[],[3162],{"type":39,"value":3163},"$COMPOSE_PROJECT_NAME",{"type":39,"value":3165},"\nVariable können wir ein generisches Template für eine solche Konfiguration erstellen.\nDadurch stellen wir sicher, dass die Traefik-Regeln einheitlich sind.",{"type":26,"tag":76,"props":3167,"children":3170},{"code":3168,"filename":3169,"language":220,"meta":7,"className":210,"style":7},"services:\n  \u003Cmain_service>:\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.$COMPOSE_PROJECT_NAME.rule=Host(`\u003Cstack_name>.example.com`)\"\n      - \"traefik.http.routers.$COMPOSE_PROJECT_NAME.entrypoints=websecure\"\n      - \"traefik.http.routers.$COMPOSE_PROJECT_NAME.tls=true\"\n      - \"traefik.http.routers.$COMPOSE_PROJECT_NAME.tls.certresolver=letsencrypt\"\n","\u003Cstack_name>/docker-compose.yaml",[3171],{"type":26,"tag":83,"props":3172,"children":3173},{"__ignoreMap":7},[3174,3185,3197,3208,3219,3231,3243,3255],{"type":26,"tag":87,"props":3175,"children":3176},{"class":89,"line":90},[3177,3181],{"type":26,"tag":87,"props":3178,"children":3179},{"style":230},[3180],{"type":39,"value":1685},{"type":26,"tag":87,"props":3182,"children":3183},{"style":236},[3184],{"type":39,"value":239},{"type":26,"tag":87,"props":3186,"children":3187},{"class":89,"line":242},[3188,3193],{"type":26,"tag":87,"props":3189,"children":3190},{"style":230},[3191],{"type":39,"value":3192},"  \u003Cmain_service>",{"type":26,"tag":87,"props":3194,"children":3195},{"style":236},[3196],{"type":39,"value":239},{"type":26,"tag":87,"props":3198,"children":3199},{"class":89,"line":256},[3200,3204],{"type":26,"tag":87,"props":3201,"children":3202},{"style":230},[3203],{"type":39,"value":2900},{"type":26,"tag":87,"props":3205,"children":3206},{"style":236},[3207],{"type":39,"value":239},{"type":26,"tag":87,"props":3209,"children":3210},{"class":89,"line":266},[3211,3215],{"type":26,"tag":87,"props":3212,"children":3213},{"style":236},[3214],{"type":39,"value":872},{"type":26,"tag":87,"props":3216,"children":3217},{"style":99},[3218],{"type":39,"value":2917},{"type":26,"tag":87,"props":3220,"children":3221},{"class":89,"line":279},[3222,3226],{"type":26,"tag":87,"props":3223,"children":3224},{"style":236},[3225],{"type":39,"value":872},{"type":26,"tag":87,"props":3227,"children":3228},{"style":99},[3229],{"type":39,"value":3230},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.rule=Host(`\u003Cstack_name>.example.com`)\"\n",{"type":26,"tag":87,"props":3232,"children":3233},{"class":89,"line":214},[3234,3238],{"type":26,"tag":87,"props":3235,"children":3236},{"style":236},[3237],{"type":39,"value":872},{"type":26,"tag":87,"props":3239,"children":3240},{"style":99},[3241],{"type":39,"value":3242},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.entrypoints=websecure\"\n",{"type":26,"tag":87,"props":3244,"children":3245},{"class":89,"line":312},[3246,3250],{"type":26,"tag":87,"props":3247,"children":3248},{"style":236},[3249],{"type":39,"value":872},{"type":26,"tag":87,"props":3251,"children":3252},{"style":99},[3253],{"type":39,"value":3254},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.tls=true\"\n",{"type":26,"tag":87,"props":3256,"children":3257},{"class":89,"line":336},[3258,3262],{"type":26,"tag":87,"props":3259,"children":3260},{"style":236},[3261],{"type":39,"value":872},{"type":26,"tag":87,"props":3263,"children":3264},{"style":99},[3265],{"type":39,"value":3266},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.tls.certresolver=letsencrypt\"\n",{"type":26,"tag":35,"props":3268,"children":3269},{},[3270],{"type":39,"value":3271},"Die gute Nachricht ist, dass Traefik es uns ermöglicht, einige Standardwerte zu konfigurieren, die den oben genannten Boilerplate-Code abdecken!",{"type":26,"tag":35,"props":3273,"children":3274},{},[3275],{"type":39,"value":3276},"Führen wir zwei einfache Konventionen ein:",{"type":26,"tag":1173,"props":3278,"children":3279},{},[3280,3291],{"type":26,"tag":128,"props":3281,"children":3282},{},[3283,3289],{"type":26,"tag":83,"props":3284,"children":3286},{"className":3285},[],[3287],{"type":39,"value":3288},"app",{"type":39,"value":3290}," als Name des \"Hauptcontainers\", damit Traefik den Datenverkehr dorthin leitet",{"type":26,"tag":128,"props":3292,"children":3293},{},[3294,3300],{"type":26,"tag":83,"props":3295,"children":3297},{"className":3296},[],[3298],{"type":39,"value":3299},"\u003Cstack_name>",{"type":39,"value":3301}," (der Name des Compose-Projekts) in der Subdomain",{"type":26,"tag":76,"props":3303,"children":3306},{"code":3304,"filename":3305,"language":220,"meta":7,"className":210,"style":7},"services:\n  app:\n    image: traefik/whoami\n","(1) whoami/docker-compose.yaml",[3307],{"type":26,"tag":83,"props":3308,"children":3309},{"__ignoreMap":7},[3310,3321,3333],{"type":26,"tag":87,"props":3311,"children":3312},{"class":89,"line":90},[3313,3317],{"type":26,"tag":87,"props":3314,"children":3315},{"style":230},[3316],{"type":39,"value":1685},{"type":26,"tag":87,"props":3318,"children":3319},{"style":236},[3320],{"type":39,"value":239},{"type":26,"tag":87,"props":3322,"children":3323},{"class":89,"line":242},[3324,3329],{"type":26,"tag":87,"props":3325,"children":3326},{"style":230},[3327],{"type":39,"value":3328},"  app",{"type":26,"tag":87,"props":3330,"children":3331},{"style":236},[3332],{"type":39,"value":239},{"type":26,"tag":87,"props":3334,"children":3335},{"class":89,"line":256},[3336,3340,3344],{"type":26,"tag":87,"props":3337,"children":3338},{"style":230},[3339],{"type":39,"value":1708},{"type":26,"tag":87,"props":3341,"children":3342},{"style":236},[3343],{"type":39,"value":304},{"type":26,"tag":87,"props":3345,"children":3346},{"style":99},[3347],{"type":39,"value":2892},{"type":26,"tag":2201,"props":3349,"children":3350},{},[],{"type":26,"tag":35,"props":3352,"children":3353},{},[3354],{"type":39,"value":3355},"Nun konfigurieren wir Traefik, um \"die Magie\" wirken zu lassen:",{"type":26,"tag":76,"props":3357,"children":3360},{"code":3358,"filename":3359,"language":220,"meta":7,"className":210,"style":7},"volumes:\n  letsencrypt:\n    \nservices:\n  traefik:\n    container_name: traefik\n    restart: always\n    image: traefik:3\n    network_mode: host\n    command:\n      - --certificatesresolvers.letsencrypt.acme.httpchallenge=true\n      - --certificatesresolvers.letsencrypt.acme.email=\u003Cyour_email_here>\n      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json\n      - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web\n\n      - --entrypoints.web.address=:80\n      - --entrypoints.websecure.address=:443\n      \n      - --entrypoints.web.http.redirections.entrypoint.to=websecure\n      - --entrypoints.web.http.redirections.entrypoint.scheme=https\n      - --entrypoints.websecure.http.tls.certresolver=letsencrypt\n\n      - --providers.docker\n      - --providers.docker.defaultrule=Host(`{{ trimPrefix `app-` .Name }}.example.com`)\n      - --providers.docker.constraints=Label(`com.docker.compose.service`,`app`)\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock:ro\n      - /letsencrypt:/letsencrypt\n","(2) traefik/docker-compose.yaml",[3361],{"type":26,"tag":83,"props":3362,"children":3363},{"__ignoreMap":7},[3364,3375,3387,3395,3406,3418,3435,3451,3467,3484,3495,3507,3519,3531,3543,3550,3562,3574,3582,3594,3606,3618,3625,3637,3649,3661,3672,3684],{"type":26,"tag":87,"props":3365,"children":3366},{"class":89,"line":90},[3367,3371],{"type":26,"tag":87,"props":3368,"children":3369},{"style":230},[3370],{"type":39,"value":1642},{"type":26,"tag":87,"props":3372,"children":3373},{"style":236},[3374],{"type":39,"value":239},{"type":26,"tag":87,"props":3376,"children":3377},{"class":89,"line":242},[3378,3383],{"type":26,"tag":87,"props":3379,"children":3380},{"style":230},[3381],{"type":39,"value":3382},"  letsencrypt",{"type":26,"tag":87,"props":3384,"children":3385},{"style":236},[3386],{"type":39,"value":239},{"type":26,"tag":87,"props":3388,"children":3389},{"class":89,"line":256},[3390],{"type":26,"tag":87,"props":3391,"children":3392},{"style":236},[3393],{"type":39,"value":3394},"    \n",{"type":26,"tag":87,"props":3396,"children":3397},{"class":89,"line":266},[3398,3402],{"type":26,"tag":87,"props":3399,"children":3400},{"style":230},[3401],{"type":39,"value":1685},{"type":26,"tag":87,"props":3403,"children":3404},{"style":236},[3405],{"type":39,"value":239},{"type":26,"tag":87,"props":3407,"children":3408},{"class":89,"line":279},[3409,3414],{"type":26,"tag":87,"props":3410,"children":3411},{"style":230},[3412],{"type":39,"value":3413},"  traefik",{"type":26,"tag":87,"props":3415,"children":3416},{"style":236},[3417],{"type":39,"value":239},{"type":26,"tag":87,"props":3419,"children":3420},{"class":89,"line":214},[3421,3426,3430],{"type":26,"tag":87,"props":3422,"children":3423},{"style":230},[3424],{"type":39,"value":3425},"    container_name",{"type":26,"tag":87,"props":3427,"children":3428},{"style":236},[3429],{"type":39,"value":304},{"type":26,"tag":87,"props":3431,"children":3432},{"style":99},[3433],{"type":39,"value":3434},"traefik\n",{"type":26,"tag":87,"props":3436,"children":3437},{"class":89,"line":312},[3438,3442,3446],{"type":26,"tag":87,"props":3439,"children":3440},{"style":230},[3441],{"type":39,"value":1725},{"type":26,"tag":87,"props":3443,"children":3444},{"style":236},[3445],{"type":39,"value":304},{"type":26,"tag":87,"props":3447,"children":3448},{"style":99},[3449],{"type":39,"value":3450},"always\n",{"type":26,"tag":87,"props":3452,"children":3453},{"class":89,"line":336},[3454,3458,3462],{"type":26,"tag":87,"props":3455,"children":3456},{"style":230},[3457],{"type":39,"value":1708},{"type":26,"tag":87,"props":3459,"children":3460},{"style":236},[3461],{"type":39,"value":304},{"type":26,"tag":87,"props":3463,"children":3464},{"style":99},[3465],{"type":39,"value":3466},"traefik:3\n",{"type":26,"tag":87,"props":3468,"children":3469},{"class":89,"line":353},[3470,3475,3479],{"type":26,"tag":87,"props":3471,"children":3472},{"style":230},[3473],{"type":39,"value":3474},"    network_mode",{"type":26,"tag":87,"props":3476,"children":3477},{"style":236},[3478],{"type":39,"value":304},{"type":26,"tag":87,"props":3480,"children":3481},{"style":99},[3482],{"type":39,"value":3483},"host\n",{"type":26,"tag":87,"props":3485,"children":3486},{"class":89,"line":366},[3487,3491],{"type":26,"tag":87,"props":3488,"children":3489},{"style":230},[3490],{"type":39,"value":1826},{"type":26,"tag":87,"props":3492,"children":3493},{"style":236},[3494],{"type":39,"value":239},{"type":26,"tag":87,"props":3496,"children":3497},{"class":89,"line":384},[3498,3502],{"type":26,"tag":87,"props":3499,"children":3500},{"style":236},[3501],{"type":39,"value":872},{"type":26,"tag":87,"props":3503,"children":3504},{"style":99},[3505],{"type":39,"value":3506},"--certificatesresolvers.letsencrypt.acme.httpchallenge=true\n",{"type":26,"tag":87,"props":3508,"children":3509},{"class":89,"line":402},[3510,3514],{"type":26,"tag":87,"props":3511,"children":3512},{"style":236},[3513],{"type":39,"value":872},{"type":26,"tag":87,"props":3515,"children":3516},{"style":99},[3517],{"type":39,"value":3518},"--certificatesresolvers.letsencrypt.acme.email=\u003Cyour_email_here>\n",{"type":26,"tag":87,"props":3520,"children":3521},{"class":89,"line":415},[3522,3526],{"type":26,"tag":87,"props":3523,"children":3524},{"style":236},[3525],{"type":39,"value":872},{"type":26,"tag":87,"props":3527,"children":3528},{"style":99},[3529],{"type":39,"value":3530},"--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json\n",{"type":26,"tag":87,"props":3532,"children":3533},{"class":89,"line":215},[3534,3538],{"type":26,"tag":87,"props":3535,"children":3536},{"style":236},[3537],{"type":39,"value":872},{"type":26,"tag":87,"props":3539,"children":3540},{"style":99},[3541],{"type":39,"value":3542},"--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web\n",{"type":26,"tag":87,"props":3544,"children":3545},{"class":89,"line":216},[3546],{"type":26,"tag":87,"props":3547,"children":3548},{"emptyLinePlaceholder":260},[3549],{"type":39,"value":263},{"type":26,"tag":87,"props":3551,"children":3552},{"class":89,"line":217},[3553,3557],{"type":26,"tag":87,"props":3554,"children":3555},{"style":236},[3556],{"type":39,"value":872},{"type":26,"tag":87,"props":3558,"children":3559},{"style":99},[3560],{"type":39,"value":3561},"--entrypoints.web.address=:80\n",{"type":26,"tag":87,"props":3563,"children":3564},{"class":89,"line":218},[3565,3569],{"type":26,"tag":87,"props":3566,"children":3567},{"style":236},[3568],{"type":39,"value":872},{"type":26,"tag":87,"props":3570,"children":3571},{"style":99},[3572],{"type":39,"value":3573},"--entrypoints.websecure.address=:443\n",{"type":26,"tag":87,"props":3575,"children":3576},{"class":89,"line":219},[3577],{"type":26,"tag":87,"props":3578,"children":3579},{"style":236},[3580],{"type":39,"value":3581},"      \n",{"type":26,"tag":87,"props":3583,"children":3584},{"class":89,"line":503},[3585,3589],{"type":26,"tag":87,"props":3586,"children":3587},{"style":236},[3588],{"type":39,"value":872},{"type":26,"tag":87,"props":3590,"children":3591},{"style":99},[3592],{"type":39,"value":3593},"--entrypoints.web.http.redirections.entrypoint.to=websecure\n",{"type":26,"tag":87,"props":3595,"children":3596},{"class":89,"line":516},[3597,3601],{"type":26,"tag":87,"props":3598,"children":3599},{"style":236},[3600],{"type":39,"value":872},{"type":26,"tag":87,"props":3602,"children":3603},{"style":99},[3604],{"type":39,"value":3605},"--entrypoints.web.http.redirections.entrypoint.scheme=https\n",{"type":26,"tag":87,"props":3607,"children":3608},{"class":89,"line":538},[3609,3613],{"type":26,"tag":87,"props":3610,"children":3611},{"style":236},[3612],{"type":39,"value":872},{"type":26,"tag":87,"props":3614,"children":3615},{"style":99},[3616],{"type":39,"value":3617},"--entrypoints.websecure.http.tls.certresolver=letsencrypt\n",{"type":26,"tag":87,"props":3619,"children":3620},{"class":89,"line":556},[3621],{"type":26,"tag":87,"props":3622,"children":3623},{"emptyLinePlaceholder":260},[3624],{"type":39,"value":263},{"type":26,"tag":87,"props":3626,"children":3627},{"class":89,"line":595},[3628,3632],{"type":26,"tag":87,"props":3629,"children":3630},{"style":236},[3631],{"type":39,"value":872},{"type":26,"tag":87,"props":3633,"children":3634},{"style":99},[3635],{"type":39,"value":3636},"--providers.docker\n",{"type":26,"tag":87,"props":3638,"children":3639},{"class":89,"line":893},[3640,3644],{"type":26,"tag":87,"props":3641,"children":3642},{"style":236},[3643],{"type":39,"value":872},{"type":26,"tag":87,"props":3645,"children":3646},{"style":99},[3647],{"type":39,"value":3648},"--providers.docker.defaultrule=Host(`{{ trimPrefix `app-` .Name }}.example.com`)\n",{"type":26,"tag":87,"props":3650,"children":3651},{"class":89,"line":905},[3652,3656],{"type":26,"tag":87,"props":3653,"children":3654},{"style":236},[3655],{"type":39,"value":872},{"type":26,"tag":87,"props":3657,"children":3658},{"style":99},[3659],{"type":39,"value":3660},"--providers.docker.constraints=Label(`com.docker.compose.service`,`app`)\n",{"type":26,"tag":87,"props":3662,"children":3663},{"class":89,"line":925},[3664,3668],{"type":26,"tag":87,"props":3665,"children":3666},{"style":230},[3667],{"type":39,"value":1742},{"type":26,"tag":87,"props":3669,"children":3670},{"style":236},[3671],{"type":39,"value":239},{"type":26,"tag":87,"props":3673,"children":3674},{"class":89,"line":941},[3675,3679],{"type":26,"tag":87,"props":3676,"children":3677},{"style":236},[3678],{"type":39,"value":872},{"type":26,"tag":87,"props":3680,"children":3681},{"style":99},[3682],{"type":39,"value":3683},"/var/run/docker.sock:/var/run/docker.sock:ro\n",{"type":26,"tag":87,"props":3685,"children":3686},{"class":89,"line":961},[3687,3691],{"type":26,"tag":87,"props":3688,"children":3689},{"style":236},[3690],{"type":39,"value":872},{"type":26,"tag":87,"props":3692,"children":3693},{"style":99},[3694],{"type":39,"value":3695},"/letsencrypt:/letsencrypt\n",{"type":26,"tag":35,"props":3697,"children":3698},{},[3699],{"type":39,"value":3700},"Erklären wir das ein wenig:",{"type":26,"tag":1173,"props":3702,"children":3703},{},[3704,3717,3722,3727,3732],{"type":26,"tag":128,"props":3705,"children":3706},{},[3707,3709,3715],{"type":39,"value":3708},"Wir konfigurieren einen ",{"type":26,"tag":42,"props":3710,"children":3712},{"href":3711},"https://letsencrypt.org/",[3713],{"type":39,"value":3714},"Let's Encrypt",{"type":39,"value":3716}," Certificates Resolver (11-14)",{"type":26,"tag":128,"props":3718,"children":3719},{},[3720],{"type":39,"value":3721},"Wir hören auf Port 80 und 443 (16-17)",{"type":26,"tag":128,"props":3723,"children":3724},{},[3725],{"type":39,"value":3726},"Wir leiten den gesamten HTTP-Verkehr auf HTTPS um (19-20)",{"type":26,"tag":128,"props":3728,"children":3729},{},[3730],{"type":39,"value":3731},"Und binden den konfigurierten Certificates Resolver daran (21)",{"type":26,"tag":128,"props":3733,"children":3734},{},[3735],{"type":39,"value":3736},"Wir richten den Docker-Provider ein (23-25)",{"type":26,"tag":3738,"props":3739,"children":3741},"h3",{"id":3740},"erklärung-für-die-zeilen-24-25",[3742],{"type":39,"value":3743},"Erklärung für die Zeilen 24-25",{"type":26,"tag":76,"props":3745,"children":3747},{"code":3746},"--providers.docker.defaultrule=Host(`{{ trimPrefix 'app-'.Name }}.example.com`)\n",[3748],{"type":26,"tag":83,"props":3749,"children":3750},{"__ignoreMap":7},[3751],{"type":39,"value":3746},{"type":26,"tag":124,"props":3753,"children":3754},{},[3755,3788],{"type":26,"tag":128,"props":3756,"children":3757},{},[3758,3764,3766,3772,3774,3779,3781,3787],{"type":26,"tag":83,"props":3759,"children":3761},{"className":3760},[],[3762],{"type":39,"value":3763},".Name",{"type":39,"value":3765}," wird automatisch als ",{"type":26,"tag":83,"props":3767,"children":3769},{"className":3768},[],[3770],{"type":39,"value":3771},"\u003Cservice-name>-\u003Cstack_name>",{"type":39,"value":3773}," generiert. Für dein ",{"type":26,"tag":83,"props":3775,"children":3777},{"className":3776},[],[3778],{"type":39,"value":2986},{"type":39,"value":3780},"-Beispiel wäre das also ",{"type":26,"tag":83,"props":3782,"children":3784},{"className":3783},[],[3785],{"type":39,"value":3786},"app-whoami",{"type":39,"value":155},{"type":26,"tag":128,"props":3789,"children":3790},{},[3791,3797,3799,3804],{"type":26,"tag":83,"props":3792,"children":3794},{"className":3793},[],[3795],{"type":39,"value":3796},"trimPrefix 'app-'.Name",{"type":39,"value":3798}," ergibt ",{"type":26,"tag":83,"props":3800,"children":3802},{"className":3801},[],[3803],{"type":39,"value":2986},{"type":39,"value":155},{"type":26,"tag":3806,"props":3807,"children":3808},"br",{},[],{"type":26,"tag":76,"props":3810,"children":3811},{"code":3660},[3812],{"type":26,"tag":83,"props":3813,"children":3814},{"__ignoreMap":7},[3815],{"type":39,"value":3660},{"type":26,"tag":35,"props":3817,"children":3818},{},[3819,3821,3826,3828,3834,3836,3842],{"type":39,"value":3820},"Alle Dienste sollten standardmäßig verfügbar sein, aber sie sollten gefiltert werden, sodass nur ",{"type":26,"tag":83,"props":3822,"children":3824},{"className":3823},[],[3825],{"type":39,"value":3288},{"type":39,"value":3827},"-Dienste berücksichtigt werden. Das Label ",{"type":26,"tag":83,"props":3829,"children":3831},{"className":3830},[],[3832],{"type":39,"value":3833},"com.docker.compose.service",{"type":39,"value":3835}," wird von ",{"type":26,"tag":83,"props":3837,"children":3839},{"className":3838},[],[3840],{"type":39,"value":3841},"docker-compose",{"type":39,"value":3843}," automatisch zu allen Containern hinzugefügt.",{"type":26,"tag":64,"props":3845,"children":3847},{"id":3846},"bonus-konfiguration",[3848],{"type":39,"value":3849},"Bonus-Konfiguration",{"type":26,"tag":35,"props":3851,"children":3852},{},[3853],{"type":39,"value":3854},"Wir können diese Konfiguration noch weiter verfeinern.",{"type":26,"tag":3738,"props":3856,"children":3858},{"id":3857},"andere-dienste-im-stack-verfügbar-machen",[3859],{"type":39,"value":3860},"Andere Dienste im Stack verfügbar machen",{"type":26,"tag":35,"props":3862,"children":3863},{},[3864],{"type":39,"value":3865},"Manchmal möchte man mehr als nur den App-Container nach außen hin öffnen.",{"type":26,"tag":35,"props":3867,"children":3868},{},[3869,3871,3876],{"type":39,"value":3870},"Die aktuelle Konfiguration leitet den Datenverkehr nur an unsere ",{"type":26,"tag":83,"props":3872,"children":3874},{"className":3873},[],[3875],{"type":39,"value":3288},{"type":39,"value":3877},"-Dienste weiter.\nUm weiterhin die Standard-Konfigurationsmethode nutzen zu können, müssen wir diese wieder aktivieren:",{"type":26,"tag":76,"props":3879,"children":3881},{"code":3880},"--providers.docker.constraints=Label(`com.docker.compose.service`,`app`) || Label(`traefik.enable`, `true`)\n",[3882],{"type":26,"tag":83,"props":3883,"children":3884},{"__ignoreMap":7},[3885],{"type":39,"value":3880},{"type":26,"tag":3738,"props":3887,"children":3889},{"id":3888},"stack-name-weicht-vom-verzeichnisnamen-ab",[3890],{"type":39,"value":3891},"Stack-Name weicht vom Verzeichnisnamen ab",{"type":26,"tag":35,"props":3893,"children":3894},{},[3895,3897,3902],{"type":39,"value":3896},"Beim Deployment der Stacks wird der Name basierend auf dem Verzeichnisnamen generiert, in dem sich die ",{"type":26,"tag":83,"props":3898,"children":3900},{"className":3899},[],[3901],{"type":39,"value":3122},{"type":39,"value":3903}," Datei befindet.\nWir können den Namen auf verschiedene Arten ändern, aber hier ist die einfachste:",{"type":26,"tag":76,"props":3905,"children":3909},{"code":3906,"filename":3907,"highlights":3908,"language":220,"meta":7,"className":210,"style":7},"name: whoami # Projektname manuell setzen\nservices:\n  app:\n    image: traefik/whoami\n","whoami-example/docker-compose.yaml",[90],[3910],{"type":26,"tag":83,"props":3911,"children":3912},{"__ignoreMap":7},[3913,3935,3946,3957],{"type":26,"tag":87,"props":3914,"children":3916},{"class":3915,"line":90},[89,293],[3917,3922,3926,3930],{"type":26,"tag":87,"props":3918,"children":3919},{"style":230},[3920],{"type":39,"value":3921},"name",{"type":26,"tag":87,"props":3923,"children":3924},{"style":236},[3925],{"type":39,"value":304},{"type":26,"tag":87,"props":3927,"children":3928},{"style":99},[3929],{"type":39,"value":2986},{"type":26,"tag":87,"props":3931,"children":3932},{"style":1540},[3933],{"type":39,"value":3934}," # Projektname manuell setzen\n",{"type":26,"tag":87,"props":3936,"children":3937},{"class":89,"line":242},[3938,3942],{"type":26,"tag":87,"props":3939,"children":3940},{"style":230},[3941],{"type":39,"value":1685},{"type":26,"tag":87,"props":3943,"children":3944},{"style":236},[3945],{"type":39,"value":239},{"type":26,"tag":87,"props":3947,"children":3948},{"class":89,"line":256},[3949,3953],{"type":26,"tag":87,"props":3950,"children":3951},{"style":230},[3952],{"type":39,"value":3328},{"type":26,"tag":87,"props":3954,"children":3955},{"style":236},[3956],{"type":39,"value":239},{"type":26,"tag":87,"props":3958,"children":3959},{"class":89,"line":266},[3960,3964,3968],{"type":26,"tag":87,"props":3961,"children":3962},{"style":230},[3963],{"type":39,"value":1708},{"type":26,"tag":87,"props":3965,"children":3966},{"style":236},[3967],{"type":39,"value":304},{"type":26,"tag":87,"props":3969,"children":3970},{"style":99},[3971],{"type":39,"value":2892},{"type":26,"tag":1192,"props":3973,"children":3974},{},[3975],{"type":39,"value":1196},{"title":7,"searchDepth":242,"depth":242,"links":3977},[3978,3979,3982],{"id":3050,"depth":242,"text":3053},{"id":3145,"depth":242,"text":3148,"children":3980},[3981],{"id":3740,"depth":256,"text":3743},{"id":3846,"depth":242,"text":3849,"children":3983},[3984,3985],{"id":3857,"depth":256,"text":3860},{"id":3888,"depth":256,"text":3891},{"_path":1233,"_dir":1234,"_draft":6,"_partial":6,"_locale":7,"slug":10,"teams":3987,"primaryTeam":1237,"firstName":1238,"lastName":1239,"prefixTitle":7,"suffixTitle":1240,"education":3988,"role":3990,"workingSince":1251,"inTheCompanySince":1252,"techSkills":3991,"skills":4005,"projects":4015,"contactDetails":4020,"_image":1324,"image":1325,"_id":1326,"_type":1327,"title":1328,"_source":1234,"_file":1329,"_stem":1330,"_extension":1327},[1236,1237],[3989],[1243,1244,1245],[1247,1248,1249,1250],[3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004],{"name":1255,"level":1256,"icon":1257},{"name":1259,"level":1256},{"name":1261,"level":1256,"icon":1262},{"name":1264,"level":1256,"icon":1265},{"name":1267,"level":1256,"icon":1268},{"name":1270,"level":1256},{"name":1272,"level":1256,"icon":1273},{"name":1275,"level":1256,"icon":1276},{"name":1278,"level":1279,"icon":1280},{"name":1282,"level":1279,"icon":1283},{"name":1285,"level":1279},{"name":1287,"level":1279,"icon":1288},{"name":1290,"level":1279,"icon":1291},[4006,4007,4008,4009,4010,4011,4012,4013,4014],{"name":1294,"level":1256},{"name":1296,"level":1256},{"name":1237,"level":1256},{"name":1299,"level":1256},{"name":1301,"level":1256},{"name":1303,"level":1279},{"name":1305,"level":1279},{"name":1307,"level":1279},{"name":1309,"level":1279},[4016,4018,4019],{"project":1312,"position":4017},[1314,1315],{"project":1317,"position":1315},{"project":1319,"position":1315},{"eMail":1321,"phone":1322,"visibility":1323},[4022,4036,4048,4060],{"_path":4023,"_dir":4024,"_draft":6,"_partial":260,"_locale":7,"name":4025,"slug":4024,"text":4026,"hoverText":4027,"image":4028,"customer":4029,"tags":4030,"_id":4032,"_type":220,"title":4033,"_source":1203,"_file":4034,"_stem":4035,"_extension":220},"/portfolio/bitburger/_teaser","bitburger","Bitburger B2B- und Marken-Shops","Launch des B2B Shops und Migration der Markenshops auf eine neue Plattform","Die Bitburger Braugruppe modernisierte ihr digitales Angebot. Nach dem Start des B2B Shops wurden fünf Markenshops auf eine gemeinsame Plattform migriert und weiterentwickelt.","/images/portfolio/bitburger/Bitburger_HuW_Glaeser.jpg","Bitburger Braugruppe",[20,4031],"e-commerce","common:portfolio:900.bitburger:_teaser.yaml","Teaser","portfolio/900.bitburger/_teaser.yaml","portfolio/900.bitburger/_teaser",{"_path":4037,"_dir":4038,"_draft":6,"_partial":260,"_locale":7,"name":4039,"slug":4038,"text":4040,"hoverText":4041,"image":4042,"customer":4043,"tags":4044,"_id":4045,"_type":220,"title":4033,"_source":1203,"_file":4046,"_stem":4047,"_extension":220},"/portfolio/purize/_teaser","purize","Purize Filters","E-Commerce für hochwertige Aktivkohlefilter","Wir unterstützen PURIZE® Filters mit einem vollständigen E-Commerce-Service inklusive Fulfillment-Lösung und Anbindung an Versanddienstleister. Unsere Expertise im Online-Handel ermöglicht dem Hersteller qualitativ hochwertiger Aktivkohlefilter \"Made in Germany\" eine reibungslose Abwicklung ihrer Bestellprozesse.","/images/portfolio/barcode-machine-verdandijpg.jpg","PURIZE® Filters",[20,4031],"common:portfolio:9000.purize:_teaser.yaml","portfolio/9000.purize/_teaser.yaml","portfolio/9000.purize/_teaser",{"_path":4049,"_dir":4050,"_draft":6,"_partial":260,"_locale":7,"name":4051,"slug":4050,"text":4052,"hoverText":4053,"image":4054,"customer":4051,"tags":4055,"_id":4057,"_type":220,"title":4033,"_source":1203,"_file":4058,"_stem":4059,"_extension":220},"/portfolio/pixelx/_teaser","pixelx","PixelX","IT-Sicherheit mit Augenmaß und Sachverstand","Für PixelX haben wir eine gezielte Sicherheitsanalyse durchgeführt, bei der wir dank unseres tiefen technischen Verständnisses eine kritische Schwachstelle identifizieren konnten. Mit minimalem Zeitaufwand erzielten wir maximalen Sicherheitsgewinn.","/images/portfolio/pixelx/pixelx_secured.png",[4056,21],"security","common:portfolio:9010.pixelx:_teaser.yaml","portfolio/9010.pixelx/_teaser.yaml","portfolio/9010.pixelx/_teaser",{"_path":4061,"_dir":4062,"_draft":6,"_partial":260,"_locale":7,"name":4063,"slug":4062,"text":4064,"hoverText":4065,"image":4066,"customer":4063,"tags":4067,"_id":4068,"_type":220,"title":4033,"_source":1203,"_file":4069,"_stem":4070,"_extension":220},"/portfolio/slimspots/_teaser","slimspots","SlimSpots","Große Datenmengen in Echtzeit verarbeiten","Für SlimSpots, einen weltweit agierenden Anbieter von Ad-Marketing-Lösungen, haben wir eine hochskalierbare Infrastruktur entwickelt, die die Verarbeitung von Billionen Datensätzen in Echtzeit ermöglicht.","/images/portfolio/slimspots/slim_spots_prtfolio.png",[1305,21],"common:portfolio:9020.slimspots:_teaser.yaml","portfolio/9020.slimspots/_teaser.yaml","portfolio/9020.slimspots/_teaser",1782284044891]