[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-/blog/tutorial/docker-compose-guia-completa":3,"prev-/blog/tutorial/docker-compose-guia-completa":1883,"next-/blog/tutorial/docker-compose-guia-completa":1886,"related-/blog/tutorial/docker-compose-guia-completa":1889},{"id":4,"title":5,"author":6,"authorUrl":7,"body":8,"category":1852,"cta":1853,"date":1856,"dateModified":1856,"description":1857,"draft":1858,"extension":1859,"faq":1860,"featured":1858,"image":1873,"imageAlt":1874,"meta":1875,"navigation":517,"path":1876,"readingTime":439,"seo":1877,"stem":1878,"tags":1879,"__hash__":1882},"blog/blog/tutorial/docker-compose-guia-completa.md","Docker Compose para principiantes — guía completa con ejemplos","Syswork México","/nosotros",{"type":9,"value":10,"toc":1836},"minimark",[11,24,27,32,39,42,67,74,90,94,101,172,175,179,182,266,276,310,313,331,338,352,355,359,362,738,744,776,790,807,812,822,846,853,857,871,1230,1232,1236,1252,1260,1264,1267,1471,1475,1485,1496,1504,1507,1537,1541,1553,1591,1658,1661,1706,1708,1712,1715,1724,1733,1742,1755,1763,1772,1776,1779,1823,1832],[12,13,14,15,19,20,23],"p",{},"Si ya sabes usar Docker para correr un contenedor individual, el siguiente paso natural es Docker Compose. En lugar de levantar cada contenedor por separado con comandos largos de ",[16,17,18],"code",{},"docker run",", defines todo en un archivo YAML y lo arrancas con un solo comando: ",[16,21,22],{},"docker compose up",".",[12,25,26],{},"En esta guía vas a aprender Docker Compose desde cero — desde la instalación hasta desplegar una aplicación completa con base de datos, caché y volúmenes persistentes.",[28,29,31],"h2",{"id":30},"requisitos-previos","Requisitos previos",[12,33,34,35,38],{},"Necesitas tener Docker instalado en tu máquina. Docker Compose viene incluido en Docker Desktop (Mac y Windows) y en las versiones recientes del paquete ",[16,36,37],{},"docker-ce"," en Linux.",[12,40,41],{},"Verifica que lo tienes instalado:",[43,44,49],"pre",{"className":45,"code":46,"language":47,"meta":48,"style":48},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","docker compose version\n","bash","",[16,50,51],{"__ignoreMap":48},[52,53,56,60,64],"span",{"class":54,"line":55},"line",1,[52,57,59],{"class":58},"sbgvK","docker",[52,61,63],{"class":62},"s_sjI"," compose",[52,65,66],{"class":62}," version\n",[12,68,69,70,73],{},"Si ves algo como ",[16,71,72],{},"Docker Compose version v2.x.x",", estás listo.",[75,76,79],"alert",{"title":77,"type":78},"Docker Compose V2","info",[12,80,81,82,85,86,89],{},"Esta guía usa la sintaxis moderna ",[16,83,84],{},"docker compose"," (con espacio). La versión antigua ",[16,87,88],{},"docker-compose"," (con guión) está deprecada desde 2023. Si aún usas la versión con guión, actualiza tu instalación de Docker.",[28,91,93],{"id":92},"qué-es-docker-compose","¿Qué es Docker Compose?",[12,95,96,97,100],{},"Docker Compose es una herramienta que permite definir y ejecutar aplicaciones multi-contenedor. En lugar de ejecutar cada contenedor manualmente, defines todos los servicios, redes y volúmenes en un archivo ",[16,98,99],{},"docker-compose.yml"," y los gestionas como una unidad.",[102,103,104,117],"table",{},[105,106,107],"thead",{},[108,109,110,114],"tr",{},[111,112,113],"th",{},"Sin Docker Compose",[111,115,116],{},"Con Docker Compose",[118,119,120,134,142,153,161],"tbody",{},[108,121,122,129],{},[123,124,125,126,128],"td",{},"Un comando ",[16,127,18],{}," por cada servicio",[123,130,131,132],{},"Un solo ",[16,133,22],{},[108,135,136,139],{},[123,137,138],{},"Redes creadas manualmente",[123,140,141],{},"Red creada automáticamente entre servicios",[108,143,144,147],{},[123,145,146],{},"Variables de entorno pasadas en la línea de comandos",[123,148,149,150],{},"Variables definidas en archivo ",[16,151,152],{},".env",[108,154,155,158],{},[123,156,157],{},"Volúmenes gestionados individualmente",[123,159,160],{},"Volúmenes declarados y gestionados juntos",[108,162,163,166],{},[123,164,165],{},"Reinicio manual si algo falla",[123,167,168,171],{},[16,169,170],{},"restart: unless-stopped"," integrado",[173,174],"ad-banner",{},[28,176,178],{"id":177},"tu-primer-docker-composeyml","Tu primer docker-compose.yml",[12,180,181],{},"Empecemos con un ejemplo mínimo: un servidor Nginx sirviendo una página estática.",[43,183,187],{"className":184,"code":185,"language":186,"meta":48,"style":48},"language-yaml shiki shiki-themes material-theme-lighter github-light github-dark","# docker-compose.yml\nservices:\n  web:\n    image: nginx:alpine\n    ports:\n      - \"8080:80\"\n    volumes:\n      - ./html:/usr/share/nginx/html:ro\n","yaml",[16,188,189,195,206,214,226,234,250,258],{"__ignoreMap":48},[52,190,191],{"class":54,"line":55},[52,192,194],{"class":193},"sutJx","# docker-compose.yml\n",[52,196,198,202],{"class":54,"line":197},2,[52,199,201],{"class":200},"sQzsp","services",[52,203,205],{"class":204},"sP7_E",":\n",[52,207,209,212],{"class":54,"line":208},3,[52,210,211],{"class":200},"  web",[52,213,205],{"class":204},[52,215,217,220,223],{"class":54,"line":216},4,[52,218,219],{"class":200},"    image",[52,221,222],{"class":204},":",[52,224,225],{"class":62}," nginx:alpine\n",[52,227,229,232],{"class":54,"line":228},5,[52,230,231],{"class":200},"    ports",[52,233,205],{"class":204},[52,235,237,240,244,247],{"class":54,"line":236},6,[52,238,239],{"class":204},"      -",[52,241,243],{"class":242},"sjJ54"," \"",[52,245,246],{"class":62},"8080:80",[52,248,249],{"class":242},"\"\n",[52,251,253,256],{"class":54,"line":252},7,[52,254,255],{"class":200},"    volumes",[52,257,205],{"class":204},[52,259,261,263],{"class":54,"line":260},8,[52,262,239],{"class":204},[52,264,265],{"class":62}," ./html:/usr/share/nginx/html:ro\n",[12,267,268,269,272,273,222],{},"Crea un directorio ",[16,270,271],{},"html"," con un archivo ",[16,274,275],{},"index.html",[43,277,279],{"className":45,"code":278,"language":47,"meta":48,"style":48},"mkdir html\necho \"\u003Ch1>Hola desde Docker Compose\u003C/h1>\" > html/index.html\n",[16,280,281,289],{"__ignoreMap":48},[52,282,283,286],{"class":54,"line":55},[52,284,285],{"class":58},"mkdir",[52,287,288],{"class":62}," html\n",[52,290,291,295,297,300,303,307],{"class":54,"line":197},[52,292,294],{"class":293},"sptTA","echo",[52,296,243],{"class":242},[52,298,299],{"class":62},"\u003Ch1>Hola desde Docker Compose\u003C/h1>",[52,301,302],{"class":242},"\"",[52,304,306],{"class":305},"smGrS"," >",[52,308,309],{"class":62}," html/index.html\n",[12,311,312],{},"Levanta el servicio:",[43,314,316],{"className":45,"code":315,"language":47,"meta":48,"style":48},"docker compose up -d\n",[16,317,318],{"__ignoreMap":48},[52,319,320,322,324,327],{"class":54,"line":55},[52,321,59],{"class":58},[52,323,63],{"class":62},[52,325,326],{"class":62}," up",[52,328,330],{"class":329},"stzsN"," -d\n",[12,332,333,334,337],{},"Abre ",[16,335,336],{},"http://localhost:8080"," y verás tu página. Para detener todo:",[43,339,341],{"className":45,"code":340,"language":47,"meta":48,"style":48},"docker compose down\n",[16,342,343],{"__ignoreMap":48},[52,344,345,347,349],{"class":54,"line":55},[52,346,59],{"class":58},[52,348,63],{"class":62},[52,350,351],{"class":62}," down\n",[12,353,354],{},"Eso es Docker Compose en su forma más simple. Ahora vamos con ejemplos reales.",[28,356,358],{"id":357},"ejemplo-1-wordpress-con-mysql","Ejemplo 1: WordPress con MySQL",[12,360,361],{},"Este es uno de los usos más comunes. Un WordPress completo con su base de datos, todo definido en un archivo:",[43,363,365],{"className":184,"code":364,"language":186,"meta":48,"style":48},"# docker-compose.yml\nservices:\n  wordpress:\n    image: wordpress:6\n    restart: unless-stopped\n    ports:\n      - \"8080:80\"\n    environment:\n      WORDPRESS_DB_HOST: db\n      WORDPRESS_DB_NAME: wordpress\n      WORDPRESS_DB_USER: wp_user\n      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}\n    volumes:\n      - wp_data:/var/www/html\n    depends_on:\n      db:\n        condition: service_healthy\n\n  db:\n    image: mysql:8\n    restart: unless-stopped\n    environment:\n      MYSQL_DATABASE: wordpress\n      MYSQL_USER: wp_user\n      MYSQL_PASSWORD: ${DB_PASSWORD}\n      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}\n    volumes:\n      - db_data:/var/lib/mysql\n    healthcheck:\n      test: [\"CMD\", \"mysqladmin\", \"ping\", \"-h\", \"localhost\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n\nvolumes:\n  wp_data:\n  db_data:\n",[16,366,367,371,377,384,393,403,409,419,426,437,448,459,470,477,485,493,501,512,519,527,537,546,553,563,573,583,594,601,609,617,675,686,697,709,714,722,730],{"__ignoreMap":48},[52,368,369],{"class":54,"line":55},[52,370,194],{"class":193},[52,372,373,375],{"class":54,"line":197},[52,374,201],{"class":200},[52,376,205],{"class":204},[52,378,379,382],{"class":54,"line":208},[52,380,381],{"class":200},"  wordpress",[52,383,205],{"class":204},[52,385,386,388,390],{"class":54,"line":216},[52,387,219],{"class":200},[52,389,222],{"class":204},[52,391,392],{"class":62}," wordpress:6\n",[52,394,395,398,400],{"class":54,"line":228},[52,396,397],{"class":200},"    restart",[52,399,222],{"class":204},[52,401,402],{"class":62}," unless-stopped\n",[52,404,405,407],{"class":54,"line":236},[52,406,231],{"class":200},[52,408,205],{"class":204},[52,410,411,413,415,417],{"class":54,"line":252},[52,412,239],{"class":204},[52,414,243],{"class":242},[52,416,246],{"class":62},[52,418,249],{"class":242},[52,420,421,424],{"class":54,"line":260},[52,422,423],{"class":200},"    environment",[52,425,205],{"class":204},[52,427,429,432,434],{"class":54,"line":428},9,[52,430,431],{"class":200},"      WORDPRESS_DB_HOST",[52,433,222],{"class":204},[52,435,436],{"class":62}," db\n",[52,438,440,443,445],{"class":54,"line":439},10,[52,441,442],{"class":200},"      WORDPRESS_DB_NAME",[52,444,222],{"class":204},[52,446,447],{"class":62}," wordpress\n",[52,449,451,454,456],{"class":54,"line":450},11,[52,452,453],{"class":200},"      WORDPRESS_DB_USER",[52,455,222],{"class":204},[52,457,458],{"class":62}," wp_user\n",[52,460,462,465,467],{"class":54,"line":461},12,[52,463,464],{"class":200},"      WORDPRESS_DB_PASSWORD",[52,466,222],{"class":204},[52,468,469],{"class":62}," ${DB_PASSWORD}\n",[52,471,473,475],{"class":54,"line":472},13,[52,474,255],{"class":200},[52,476,205],{"class":204},[52,478,480,482],{"class":54,"line":479},14,[52,481,239],{"class":204},[52,483,484],{"class":62}," wp_data:/var/www/html\n",[52,486,488,491],{"class":54,"line":487},15,[52,489,490],{"class":200},"    depends_on",[52,492,205],{"class":204},[52,494,496,499],{"class":54,"line":495},16,[52,497,498],{"class":200},"      db",[52,500,205],{"class":204},[52,502,504,507,509],{"class":54,"line":503},17,[52,505,506],{"class":200},"        condition",[52,508,222],{"class":204},[52,510,511],{"class":62}," service_healthy\n",[52,513,515],{"class":54,"line":514},18,[52,516,518],{"emptyLinePlaceholder":517},true,"\n",[52,520,522,525],{"class":54,"line":521},19,[52,523,524],{"class":200},"  db",[52,526,205],{"class":204},[52,528,530,532,534],{"class":54,"line":529},20,[52,531,219],{"class":200},[52,533,222],{"class":204},[52,535,536],{"class":62}," mysql:8\n",[52,538,540,542,544],{"class":54,"line":539},21,[52,541,397],{"class":200},[52,543,222],{"class":204},[52,545,402],{"class":62},[52,547,549,551],{"class":54,"line":548},22,[52,550,423],{"class":200},[52,552,205],{"class":204},[52,554,556,559,561],{"class":54,"line":555},23,[52,557,558],{"class":200},"      MYSQL_DATABASE",[52,560,222],{"class":204},[52,562,447],{"class":62},[52,564,566,569,571],{"class":54,"line":565},24,[52,567,568],{"class":200},"      MYSQL_USER",[52,570,222],{"class":204},[52,572,458],{"class":62},[52,574,576,579,581],{"class":54,"line":575},25,[52,577,578],{"class":200},"      MYSQL_PASSWORD",[52,580,222],{"class":204},[52,582,469],{"class":62},[52,584,586,589,591],{"class":54,"line":585},26,[52,587,588],{"class":200},"      MYSQL_ROOT_PASSWORD",[52,590,222],{"class":204},[52,592,593],{"class":62}," ${DB_ROOT_PASSWORD}\n",[52,595,597,599],{"class":54,"line":596},27,[52,598,255],{"class":200},[52,600,205],{"class":204},[52,602,604,606],{"class":54,"line":603},28,[52,605,239],{"class":204},[52,607,608],{"class":62}," db_data:/var/lib/mysql\n",[52,610,612,615],{"class":54,"line":611},29,[52,613,614],{"class":200},"    healthcheck",[52,616,205],{"class":204},[52,618,620,623,625,628,630,633,635,638,640,643,645,647,649,652,654,656,658,661,663,665,667,670,672],{"class":54,"line":619},30,[52,621,622],{"class":200},"      test",[52,624,222],{"class":204},[52,626,627],{"class":204}," [",[52,629,302],{"class":242},[52,631,632],{"class":62},"CMD",[52,634,302],{"class":242},[52,636,637],{"class":204},",",[52,639,243],{"class":242},[52,641,642],{"class":62},"mysqladmin",[52,644,302],{"class":242},[52,646,637],{"class":204},[52,648,243],{"class":242},[52,650,651],{"class":62},"ping",[52,653,302],{"class":242},[52,655,637],{"class":204},[52,657,243],{"class":242},[52,659,660],{"class":62},"-h",[52,662,302],{"class":242},[52,664,637],{"class":204},[52,666,243],{"class":242},[52,668,669],{"class":62},"localhost",[52,671,302],{"class":242},[52,673,674],{"class":204},"]\n",[52,676,678,681,683],{"class":54,"line":677},31,[52,679,680],{"class":200},"      interval",[52,682,222],{"class":204},[52,684,685],{"class":62}," 10s\n",[52,687,689,692,694],{"class":54,"line":688},32,[52,690,691],{"class":200},"      timeout",[52,693,222],{"class":204},[52,695,696],{"class":62}," 5s\n",[52,698,700,703,705],{"class":54,"line":699},33,[52,701,702],{"class":200},"      retries",[52,704,222],{"class":204},[52,706,708],{"class":707},"srdBf"," 5\n",[52,710,712],{"class":54,"line":711},34,[52,713,518],{"emptyLinePlaceholder":517},[52,715,717,720],{"class":54,"line":716},35,[52,718,719],{"class":200},"volumes",[52,721,205],{"class":204},[52,723,725,728],{"class":54,"line":724},36,[52,726,727],{"class":200},"  wp_data",[52,729,205],{"class":204},[52,731,733,736],{"class":54,"line":732},37,[52,734,735],{"class":200},"  db_data",[52,737,205],{"class":204},[12,739,740,741,743],{},"Crea un archivo ",[16,742,152],{}," con las contraseñas:",[43,745,747],{"className":45,"code":746,"language":47,"meta":48,"style":48},"# .env\nDB_PASSWORD=contraseña_segura_123\nDB_ROOT_PASSWORD=root_seguro_456\n",[16,748,749,754,766],{"__ignoreMap":48},[52,750,751],{"class":54,"line":55},[52,752,753],{"class":193},"# .env\n",[52,755,756,760,763],{"class":54,"line":197},[52,757,759],{"class":758},"su5hD","DB_PASSWORD",[52,761,762],{"class":305},"=",[52,764,765],{"class":62},"contraseña_segura_123\n",[52,767,768,771,773],{"class":54,"line":208},[52,769,770],{"class":758},"DB_ROOT_PASSWORD",[52,772,762],{"class":305},[52,774,775],{"class":62},"root_seguro_456\n",[43,777,778],{"className":45,"code":315,"language":47,"meta":48,"style":48},[16,779,780],{"__ignoreMap":48},[52,781,782,784,786,788],{"class":54,"line":55},[52,783,59],{"class":58},[52,785,63],{"class":62},[52,787,326],{"class":62},[52,789,330],{"class":329},[75,791,794],{"title":792,"type":793},"Seguridad","warning",[12,795,796,797,799,800,802,803,806],{},"Nunca pongas contraseñas directamente en el ",[16,798,99],{},". Usa un archivo ",[16,801,152],{}," y agrégalo a tu ",[16,804,805],{},".gitignore"," para que no se suba al repositorio.",[808,809,811],"h3",{"id":810},"conceptos-clave-de-este-ejemplo","Conceptos clave de este ejemplo",[12,813,814,821],{},[815,816,817,820],"strong",{},[16,818,819],{},"depends_on"," con healthcheck"," — WordPress no arranca hasta que MySQL esté saludable. Sin esto, WordPress podría intentar conectarse antes de que la base de datos esté lista y fallar.",[12,823,824,829,830,833,834,837,838,841,842,845],{},[815,825,826,828],{},[16,827,719],{}," nombrados"," — ",[16,831,832],{},"wp_data"," y ",[16,835,836],{},"db_data"," son volúmenes persistentes. Si haces ",[16,839,840],{},"docker compose down",", los datos se conservan. Si haces ",[16,843,844],{},"docker compose down -v",", se eliminan los volúmenes y los datos.",[12,847,848,852],{},[815,849,850],{},[16,851,170],{}," — Si el contenedor se cae o el servidor se reinicia, Docker lo levanta automáticamente. Solo se detiene si tú lo detienes manualmente.",[28,854,856],{"id":855},"ejemplo-2-aplicación-con-postgresql-y-redis","Ejemplo 2: Aplicación con PostgreSQL y Redis",[12,858,859,860,865,866,870],{},"Un stack más realista para una aplicación empresarial — una API con ",[861,862,864],"a",{"href":863},"/tecnologias/postgresql","PostgreSQL"," como base de datos y ",[861,867,869],{"href":868},"/tecnologias/redis","Redis"," como caché:",[43,872,874],{"className":184,"code":873,"language":186,"meta":48,"style":48},"# docker-compose.yml\nservices:\n  app:\n    build:\n      context: .\n      dockerfile: Dockerfile\n    restart: unless-stopped\n    ports:\n      - \"3000:3000\"\n    environment:\n      DATABASE_URL: postgresql://app:${DB_PASSWORD}@db:5432/miapp\n      REDIS_URL: redis://cache:6379\n      NODE_ENV: production\n    depends_on:\n      db:\n        condition: service_healthy\n      cache:\n        condition: service_started\n\n  db:\n    image: postgres:16-alpine\n    restart: unless-stopped\n    environment:\n      POSTGRES_DB: miapp\n      POSTGRES_USER: app\n      POSTGRES_PASSWORD: ${DB_PASSWORD}\n    volumes:\n      - pg_data:/var/lib/postgresql/data\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U app -d miapp\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n\n  cache:\n    image: redis:7-alpine\n    restart: unless-stopped\n    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru\n    volumes:\n      - redis_data:/data\n\nvolumes:\n  pg_data:\n  redis_data:\n",[16,875,876,880,886,893,900,910,920,928,934,945,951,961,971,981,987,993,1001,1008,1017,1021,1027,1036,1044,1050,1060,1070,1079,1085,1092,1098,1124,1132,1140,1148,1152,1159,1168,1176,1187,1194,1202,1207,1214,1222],{"__ignoreMap":48},[52,877,878],{"class":54,"line":55},[52,879,194],{"class":193},[52,881,882,884],{"class":54,"line":197},[52,883,201],{"class":200},[52,885,205],{"class":204},[52,887,888,891],{"class":54,"line":208},[52,889,890],{"class":200},"  app",[52,892,205],{"class":204},[52,894,895,898],{"class":54,"line":216},[52,896,897],{"class":200},"    build",[52,899,205],{"class":204},[52,901,902,905,907],{"class":54,"line":228},[52,903,904],{"class":200},"      context",[52,906,222],{"class":204},[52,908,909],{"class":707}," .\n",[52,911,912,915,917],{"class":54,"line":236},[52,913,914],{"class":200},"      dockerfile",[52,916,222],{"class":204},[52,918,919],{"class":62}," Dockerfile\n",[52,921,922,924,926],{"class":54,"line":252},[52,923,397],{"class":200},[52,925,222],{"class":204},[52,927,402],{"class":62},[52,929,930,932],{"class":54,"line":260},[52,931,231],{"class":200},[52,933,205],{"class":204},[52,935,936,938,940,943],{"class":54,"line":428},[52,937,239],{"class":204},[52,939,243],{"class":242},[52,941,942],{"class":62},"3000:3000",[52,944,249],{"class":242},[52,946,947,949],{"class":54,"line":439},[52,948,423],{"class":200},[52,950,205],{"class":204},[52,952,953,956,958],{"class":54,"line":450},[52,954,955],{"class":200},"      DATABASE_URL",[52,957,222],{"class":204},[52,959,960],{"class":62}," postgresql://app:${DB_PASSWORD}@db:5432/miapp\n",[52,962,963,966,968],{"class":54,"line":461},[52,964,965],{"class":200},"      REDIS_URL",[52,967,222],{"class":204},[52,969,970],{"class":62}," redis://cache:6379\n",[52,972,973,976,978],{"class":54,"line":472},[52,974,975],{"class":200},"      NODE_ENV",[52,977,222],{"class":204},[52,979,980],{"class":62}," production\n",[52,982,983,985],{"class":54,"line":479},[52,984,490],{"class":200},[52,986,205],{"class":204},[52,988,989,991],{"class":54,"line":487},[52,990,498],{"class":200},[52,992,205],{"class":204},[52,994,995,997,999],{"class":54,"line":495},[52,996,506],{"class":200},[52,998,222],{"class":204},[52,1000,511],{"class":62},[52,1002,1003,1006],{"class":54,"line":503},[52,1004,1005],{"class":200},"      cache",[52,1007,205],{"class":204},[52,1009,1010,1012,1014],{"class":54,"line":514},[52,1011,506],{"class":200},[52,1013,222],{"class":204},[52,1015,1016],{"class":62}," service_started\n",[52,1018,1019],{"class":54,"line":521},[52,1020,518],{"emptyLinePlaceholder":517},[52,1022,1023,1025],{"class":54,"line":529},[52,1024,524],{"class":200},[52,1026,205],{"class":204},[52,1028,1029,1031,1033],{"class":54,"line":539},[52,1030,219],{"class":200},[52,1032,222],{"class":204},[52,1034,1035],{"class":62}," postgres:16-alpine\n",[52,1037,1038,1040,1042],{"class":54,"line":548},[52,1039,397],{"class":200},[52,1041,222],{"class":204},[52,1043,402],{"class":62},[52,1045,1046,1048],{"class":54,"line":555},[52,1047,423],{"class":200},[52,1049,205],{"class":204},[52,1051,1052,1055,1057],{"class":54,"line":565},[52,1053,1054],{"class":200},"      POSTGRES_DB",[52,1056,222],{"class":204},[52,1058,1059],{"class":62}," miapp\n",[52,1061,1062,1065,1067],{"class":54,"line":575},[52,1063,1064],{"class":200},"      POSTGRES_USER",[52,1066,222],{"class":204},[52,1068,1069],{"class":62}," app\n",[52,1071,1072,1075,1077],{"class":54,"line":585},[52,1073,1074],{"class":200},"      POSTGRES_PASSWORD",[52,1076,222],{"class":204},[52,1078,469],{"class":62},[52,1080,1081,1083],{"class":54,"line":596},[52,1082,255],{"class":200},[52,1084,205],{"class":204},[52,1086,1087,1089],{"class":54,"line":603},[52,1088,239],{"class":204},[52,1090,1091],{"class":62}," pg_data:/var/lib/postgresql/data\n",[52,1093,1094,1096],{"class":54,"line":611},[52,1095,614],{"class":200},[52,1097,205],{"class":204},[52,1099,1100,1102,1104,1106,1108,1111,1113,1115,1117,1120,1122],{"class":54,"line":619},[52,1101,622],{"class":200},[52,1103,222],{"class":204},[52,1105,627],{"class":204},[52,1107,302],{"class":242},[52,1109,1110],{"class":62},"CMD-SHELL",[52,1112,302],{"class":242},[52,1114,637],{"class":204},[52,1116,243],{"class":242},[52,1118,1119],{"class":62},"pg_isready -U app -d miapp",[52,1121,302],{"class":242},[52,1123,674],{"class":204},[52,1125,1126,1128,1130],{"class":54,"line":677},[52,1127,680],{"class":200},[52,1129,222],{"class":204},[52,1131,685],{"class":62},[52,1133,1134,1136,1138],{"class":54,"line":688},[52,1135,691],{"class":200},[52,1137,222],{"class":204},[52,1139,696],{"class":62},[52,1141,1142,1144,1146],{"class":54,"line":699},[52,1143,702],{"class":200},[52,1145,222],{"class":204},[52,1147,708],{"class":707},[52,1149,1150],{"class":54,"line":711},[52,1151,518],{"emptyLinePlaceholder":517},[52,1153,1154,1157],{"class":54,"line":716},[52,1155,1156],{"class":200},"  cache",[52,1158,205],{"class":204},[52,1160,1161,1163,1165],{"class":54,"line":724},[52,1162,219],{"class":200},[52,1164,222],{"class":204},[52,1166,1167],{"class":62}," redis:7-alpine\n",[52,1169,1170,1172,1174],{"class":54,"line":732},[52,1171,397],{"class":200},[52,1173,222],{"class":204},[52,1175,402],{"class":62},[52,1177,1179,1182,1184],{"class":54,"line":1178},38,[52,1180,1181],{"class":200},"    command",[52,1183,222],{"class":204},[52,1185,1186],{"class":62}," redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru\n",[52,1188,1190,1192],{"class":54,"line":1189},39,[52,1191,255],{"class":200},[52,1193,205],{"class":204},[52,1195,1197,1199],{"class":54,"line":1196},40,[52,1198,239],{"class":204},[52,1200,1201],{"class":62}," redis_data:/data\n",[52,1203,1205],{"class":54,"line":1204},41,[52,1206,518],{"emptyLinePlaceholder":517},[52,1208,1210,1212],{"class":54,"line":1209},42,[52,1211,719],{"class":200},[52,1213,205],{"class":204},[52,1215,1217,1220],{"class":54,"line":1216},43,[52,1218,1219],{"class":200},"  pg_data",[52,1221,205],{"class":204},[52,1223,1225,1228],{"class":54,"line":1224},44,[52,1226,1227],{"class":200},"  redis_data",[52,1229,205],{"class":204},[173,1231],{},[808,1233,1235],{"id":1234},"conceptos-nuevos","Conceptos nuevos",[12,1237,1238,1243,1244,1247,1248,1251],{},[815,1239,1240],{},[16,1241,1242],{},"build"," — En lugar de usar una imagen pre-construida, Docker Compose construye la imagen desde tu ",[16,1245,1246],{},"Dockerfile",". Cada vez que hagas ",[16,1249,1250],{},"docker compose build",", se reconstruye con tus cambios.",[12,1253,1254,1259],{},[815,1255,1256],{},[16,1257,1258],{},"command"," — Sobreescribe el comando por defecto del contenedor. Aquí configuramos Redis con un límite de memoria de 256 MB y política de evicción LRU (elimina las claves menos usadas cuando se llena).",[28,1261,1263],{"id":1262},"comandos-esenciales","Comandos esenciales",[12,1265,1266],{},"Estos son los comandos que vas a usar todos los días:",[43,1268,1270],{"className":45,"code":1269,"language":47,"meta":48,"style":48},"# Levantar todos los servicios en background\ndocker compose up -d\n\n# Ver logs de todos los servicios\ndocker compose logs -f\n\n# Ver logs de un servicio específico\ndocker compose logs -f db\n\n# Detener todos los servicios (conserva datos)\ndocker compose down\n\n# Detener y eliminar volúmenes (¡borra datos!)\ndocker compose down -v\n\n# Reconstruir imágenes y levantar\ndocker compose up -d --build\n\n# Ver estatus de los servicios\ndocker compose ps\n\n# Ejecutar un comando dentro de un contenedor\ndocker compose exec db psql -U app -d miapp\n\n# Escalar un servicio (levantar múltiples réplicas)\ndocker compose up -d --scale app=3\n",[16,1271,1272,1277,1287,1291,1296,1308,1312,1317,1330,1334,1339,1347,1351,1356,1368,1372,1377,1391,1395,1400,1409,1413,1418,1443,1447,1452],{"__ignoreMap":48},[52,1273,1274],{"class":54,"line":55},[52,1275,1276],{"class":193},"# Levantar todos los servicios en background\n",[52,1278,1279,1281,1283,1285],{"class":54,"line":197},[52,1280,59],{"class":58},[52,1282,63],{"class":62},[52,1284,326],{"class":62},[52,1286,330],{"class":329},[52,1288,1289],{"class":54,"line":208},[52,1290,518],{"emptyLinePlaceholder":517},[52,1292,1293],{"class":54,"line":216},[52,1294,1295],{"class":193},"# Ver logs de todos los servicios\n",[52,1297,1298,1300,1302,1305],{"class":54,"line":228},[52,1299,59],{"class":58},[52,1301,63],{"class":62},[52,1303,1304],{"class":62}," logs",[52,1306,1307],{"class":329}," -f\n",[52,1309,1310],{"class":54,"line":236},[52,1311,518],{"emptyLinePlaceholder":517},[52,1313,1314],{"class":54,"line":252},[52,1315,1316],{"class":193},"# Ver logs de un servicio específico\n",[52,1318,1319,1321,1323,1325,1328],{"class":54,"line":260},[52,1320,59],{"class":58},[52,1322,63],{"class":62},[52,1324,1304],{"class":62},[52,1326,1327],{"class":329}," -f",[52,1329,436],{"class":62},[52,1331,1332],{"class":54,"line":428},[52,1333,518],{"emptyLinePlaceholder":517},[52,1335,1336],{"class":54,"line":439},[52,1337,1338],{"class":193},"# Detener todos los servicios (conserva datos)\n",[52,1340,1341,1343,1345],{"class":54,"line":450},[52,1342,59],{"class":58},[52,1344,63],{"class":62},[52,1346,351],{"class":62},[52,1348,1349],{"class":54,"line":461},[52,1350,518],{"emptyLinePlaceholder":517},[52,1352,1353],{"class":54,"line":472},[52,1354,1355],{"class":193},"# Detener y eliminar volúmenes (¡borra datos!)\n",[52,1357,1358,1360,1362,1365],{"class":54,"line":479},[52,1359,59],{"class":58},[52,1361,63],{"class":62},[52,1363,1364],{"class":62}," down",[52,1366,1367],{"class":329}," -v\n",[52,1369,1370],{"class":54,"line":487},[52,1371,518],{"emptyLinePlaceholder":517},[52,1373,1374],{"class":54,"line":495},[52,1375,1376],{"class":193},"# Reconstruir imágenes y levantar\n",[52,1378,1379,1381,1383,1385,1388],{"class":54,"line":503},[52,1380,59],{"class":58},[52,1382,63],{"class":62},[52,1384,326],{"class":62},[52,1386,1387],{"class":329}," -d",[52,1389,1390],{"class":329}," --build\n",[52,1392,1393],{"class":54,"line":514},[52,1394,518],{"emptyLinePlaceholder":517},[52,1396,1397],{"class":54,"line":521},[52,1398,1399],{"class":193},"# Ver estatus de los servicios\n",[52,1401,1402,1404,1406],{"class":54,"line":529},[52,1403,59],{"class":58},[52,1405,63],{"class":62},[52,1407,1408],{"class":62}," ps\n",[52,1410,1411],{"class":54,"line":539},[52,1412,518],{"emptyLinePlaceholder":517},[52,1414,1415],{"class":54,"line":548},[52,1416,1417],{"class":193},"# Ejecutar un comando dentro de un contenedor\n",[52,1419,1420,1422,1424,1427,1430,1433,1436,1439,1441],{"class":54,"line":555},[52,1421,59],{"class":58},[52,1423,63],{"class":62},[52,1425,1426],{"class":62}," exec",[52,1428,1429],{"class":62}," db",[52,1431,1432],{"class":62}," psql",[52,1434,1435],{"class":329}," -U",[52,1437,1438],{"class":62}," app",[52,1440,1387],{"class":329},[52,1442,1059],{"class":62},[52,1444,1445],{"class":54,"line":565},[52,1446,518],{"emptyLinePlaceholder":517},[52,1448,1449],{"class":54,"line":575},[52,1450,1451],{"class":193},"# Escalar un servicio (levantar múltiples réplicas)\n",[52,1453,1454,1456,1458,1460,1462,1465,1468],{"class":54,"line":585},[52,1455,59],{"class":58},[52,1457,63],{"class":62},[52,1459,326],{"class":62},[52,1461,1387],{"class":329},[52,1463,1464],{"class":329}," --scale",[52,1466,1467],{"class":62}," app=",[52,1469,1470],{"class":707},"3\n",[28,1472,1474],{"id":1473},"redes-en-docker-compose","Redes en Docker Compose",[12,1476,1477,1478,1480,1481,1484],{},"Docker Compose crea automáticamente una red para tu stack. Todos los servicios definidos en el mismo ",[16,1479,99],{}," pueden comunicarse entre sí usando el ",[815,1482,1483],{},"nombre del servicio"," como hostname.",[12,1486,1487,1488,1491,1492,1495],{},"En el ejemplo anterior, la aplicación se conecta a PostgreSQL usando ",[16,1489,1490],{},"db"," como hostname y a Redis usando ",[16,1493,1494],{},"cache",". No necesitas IPs, no necesitas configurar nada — Docker Compose lo resuelve automáticamente.",[43,1497,1502],{"className":1498,"code":1500,"language":1501},[1499],"language-text","┌─────────────────────────────────────────┐\n│        Red: miapp_default               │\n│                                         │\n│  ┌─────┐    ┌──────┐    ┌───────┐      │\n│  │ app │───▶│  db  │    │ cache │      │\n│  │:3000│    │:5432 │    │:6379  │      │\n│  └─────┘    └──────┘    └───────┘      │\n│      │                                   │\n│      ▼                                   │\n│  Puerto 3000 expuesto al host           │\n└─────────────────────────────────────────┘\n","text",[16,1503,1500],{"__ignoreMap":48},[12,1505,1506],{},"Si necesitas que dos stacks diferentes se comuniquen, puedes crear redes externas:",[43,1508,1510],{"className":184,"code":1509,"language":186,"meta":48,"style":48},"networks:\n  shared:\n    external: true\n",[16,1511,1512,1519,1526],{"__ignoreMap":48},[52,1513,1514,1517],{"class":54,"line":55},[52,1515,1516],{"class":200},"networks",[52,1518,205],{"class":204},[52,1520,1521,1524],{"class":54,"line":197},[52,1522,1523],{"class":200},"  shared",[52,1525,205],{"class":204},[52,1527,1528,1531,1533],{"class":54,"line":208},[52,1529,1530],{"class":200},"    external",[52,1532,222],{"class":204},[52,1534,1536],{"class":1535},"syTEX"," true\n",[28,1538,1540],{"id":1539},"variables-de-entorno-y-archivos-env","Variables de entorno y archivos .env",[12,1542,1543,1544,1546,1547,1549,1550,222],{},"Docker Compose lee automáticamente el archivo ",[16,1545,152],{}," en el mismo directorio que tu ",[16,1548,99],{},". Las variables se sustituyen con la sintaxis ",[16,1551,1552],{},"${VARIABLE}",[43,1554,1556],{"className":45,"code":1555,"language":47,"meta":48,"style":48},"# .env\nDB_PASSWORD=mi_contraseña_segura\nPOSTGRES_VERSION=16\nAPP_PORT=3000\n",[16,1557,1558,1562,1571,1581],{"__ignoreMap":48},[52,1559,1560],{"class":54,"line":55},[52,1561,753],{"class":193},[52,1563,1564,1566,1568],{"class":54,"line":197},[52,1565,759],{"class":758},[52,1567,762],{"class":305},[52,1569,1570],{"class":62},"mi_contraseña_segura\n",[52,1572,1573,1576,1578],{"class":54,"line":208},[52,1574,1575],{"class":758},"POSTGRES_VERSION",[52,1577,762],{"class":305},[52,1579,1580],{"class":62},"16\n",[52,1582,1583,1586,1588],{"class":54,"line":216},[52,1584,1585],{"class":758},"APP_PORT",[52,1587,762],{"class":305},[52,1589,1590],{"class":62},"3000\n",[43,1592,1594],{"className":184,"code":1593,"language":186,"meta":48,"style":48},"# docker-compose.yml\nservices:\n  db:\n    image: postgres:${POSTGRES_VERSION}-alpine\n    environment:\n      POSTGRES_PASSWORD: ${DB_PASSWORD}\n  app:\n    ports:\n      - \"${APP_PORT}:3000\"\n",[16,1595,1596,1600,1606,1612,1621,1627,1635,1641,1647],{"__ignoreMap":48},[52,1597,1598],{"class":54,"line":55},[52,1599,194],{"class":193},[52,1601,1602,1604],{"class":54,"line":197},[52,1603,201],{"class":200},[52,1605,205],{"class":204},[52,1607,1608,1610],{"class":54,"line":208},[52,1609,524],{"class":200},[52,1611,205],{"class":204},[52,1613,1614,1616,1618],{"class":54,"line":216},[52,1615,219],{"class":200},[52,1617,222],{"class":204},[52,1619,1620],{"class":62}," postgres:${POSTGRES_VERSION}-alpine\n",[52,1622,1623,1625],{"class":54,"line":228},[52,1624,423],{"class":200},[52,1626,205],{"class":204},[52,1628,1629,1631,1633],{"class":54,"line":236},[52,1630,1074],{"class":200},[52,1632,222],{"class":204},[52,1634,469],{"class":62},[52,1636,1637,1639],{"class":54,"line":252},[52,1638,890],{"class":200},[52,1640,205],{"class":204},[52,1642,1643,1645],{"class":54,"line":260},[52,1644,231],{"class":200},[52,1646,205],{"class":204},[52,1648,1649,1651,1653,1656],{"class":54,"line":428},[52,1650,239],{"class":204},[52,1652,243],{"class":242},[52,1654,1655],{"class":62},"${APP_PORT}:3000",[52,1657,249],{"class":242},[12,1659,1660],{},"Para diferentes entornos (desarrollo, staging, producción), puedes tener archivos separados:",[43,1662,1664],{"className":45,"code":1663,"language":47,"meta":48,"style":48},"# Desarrollo (usa .env por defecto)\ndocker compose up -d\n\n# Producción (usa .env.production)\ndocker compose --env-file .env.production up -d\n",[16,1665,1666,1671,1681,1685,1690],{"__ignoreMap":48},[52,1667,1668],{"class":54,"line":55},[52,1669,1670],{"class":193},"# Desarrollo (usa .env por defecto)\n",[52,1672,1673,1675,1677,1679],{"class":54,"line":197},[52,1674,59],{"class":58},[52,1676,63],{"class":62},[52,1678,326],{"class":62},[52,1680,330],{"class":329},[52,1682,1683],{"class":54,"line":208},[52,1684,518],{"emptyLinePlaceholder":517},[52,1686,1687],{"class":54,"line":216},[52,1688,1689],{"class":193},"# Producción (usa .env.production)\n",[52,1691,1692,1694,1696,1699,1702,1704],{"class":54,"line":228},[52,1693,59],{"class":58},[52,1695,63],{"class":62},[52,1697,1698],{"class":329}," --env-file",[52,1700,1701],{"class":62}," .env.production",[52,1703,326],{"class":62},[52,1705,330],{"class":329},[173,1707],{},[28,1709,1711],{"id":1710},"buenas-prácticas","Buenas prácticas",[12,1713,1714],{},"Después de usar Docker Compose en decenas de proyectos empresariales, estas son las prácticas que recomendamos:",[12,1716,1717,1720,1721,23],{},[815,1718,1719],{},"Siempre usa volúmenes nombrados para datos persistentes"," — Los volúmenes anónimos son difíciles de rastrear y respaldar. Los nombrados son explícitos y aparecen en ",[16,1722,1723],{},"docker volume ls",[12,1725,1726,1729,1730,1732],{},[815,1727,1728],{},"Siempre define healthchecks en bases de datos"," — Un ",[16,1731,819],{}," sin healthcheck solo espera a que el contenedor arranque, no a que el servicio esté listo. La base de datos puede tardar varios segundos en aceptar conexiones después de arrancar.",[12,1734,1735,1738,1739,1741],{},[815,1736,1737],{},"Nunca pongas secretos en el docker-compose.yml"," — Usa ",[16,1740,152],{}," para desarrollo y Docker Secrets o variables de entorno del sistema para producción.",[12,1743,1744,1738,1747,1750,1751,1754],{},[815,1745,1746],{},"Fija versiones de imagen",[16,1748,1749],{},"postgres:16-alpine",", no ",[16,1752,1753],{},"postgres:latest",". Latest puede cambiar en cualquier momento y romper tu aplicación sin aviso.",[12,1756,1757,1762],{},[815,1758,1759,1760],{},"Usa ",[16,1761,170],{}," — Tus contenedores se recuperan automáticamente de fallos y reinicios del servidor, pero puedes detenerlos manualmente cuando necesites.",[12,1764,1765,1771],{},[815,1766,1759,1767,1770],{},[16,1768,1769],{},"docker compose logs -f"," para debugging"," — Es tu primera herramienta de diagnóstico. Si algo no funciona, los logs te dirán qué pasó.",[28,1773,1775],{"id":1774},"siguientes-pasos","Siguientes pasos",[12,1777,1778],{},"Con Docker Compose dominado, el siguiente nivel es:",[1780,1781,1782,1793,1805,1814],"ul",{},[1783,1784,1785,1788,1789],"li",{},[815,1786,1787],{},"Docker en producción"," — configurar TLS, backups automatizados de volúmenes y monitoreo con ",[861,1790,1792],{"href":1791},"/tecnologias/docker","Prometheus y Grafana",[1783,1794,1795,1798,1799,833,1801,1804],{},[815,1796,1797],{},"CI/CD"," — integrar ",[16,1800,1250],{},[16,1802,1803],{},"docker compose push"," en tu pipeline de GitHub Actions o GitLab CI",[1783,1806,1807,1813],{},[815,1808,1809],{},[861,1810,1812],{"href":1811},"/tecnologias/kubernetes","Kubernetes"," — cuando necesitas múltiples servidores, auto-scaling y alta disponibilidad real",[1783,1815,1816,1822],{},[815,1817,1818],{},[861,1819,1821],{"href":1820},"/tecnologias/proxmox","Proxmox"," — virtualización para aislar tus hosts de Docker en ambientes empresariales",[1824,1825],"call-to-action",{"description":1826,"eyebrow":1827,"icon":1828,"label":1829,"title":1830,"to":1831},"Te ayudamos a diseñar la arquitectura de contenedores y Docker Compose para tu ERP, CRM o aplicación a medida.","Contenedores empresariales","i-lucide-container","Agendar consultoría","¿Necesitas ayuda para containerizar tu aplicación?","/contacto",[1833,1834,1835],"style",{},"html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":48,"searchDepth":197,"depth":208,"links":1837},[1838,1839,1840,1841,1844,1847,1848,1849,1850,1851],{"id":30,"depth":197,"text":31},{"id":92,"depth":197,"text":93},{"id":177,"depth":197,"text":178},{"id":357,"depth":197,"text":358,"children":1842},[1843],{"id":810,"depth":208,"text":811},{"id":855,"depth":197,"text":856,"children":1845},[1846],{"id":1234,"depth":208,"text":1235},{"id":1262,"depth":197,"text":1263},{"id":1473,"depth":197,"text":1474},{"id":1539,"depth":197,"text":1540},{"id":1710,"depth":197,"text":1711},{"id":1774,"depth":197,"text":1775},"tutorial",{"title":1854,"description":1855,"label":1829,"to":1831,"icon":1828},"¿Necesitas ayuda para containerizar tu aplicación empresarial?","Te ayudamos a diseñar la arquitectura de contenedores, Docker Compose y despliegue para tu ERP, CRM o aplicación a medida.","2026-02-20","Aprende a usar Docker Compose desde cero para levantar aplicaciones multi-contenedor con un solo comando. Incluye ejemplos prácticos con WordPress, PostgreSQL y más.",false,"md",[1861,1864,1867,1870],{"question":1862,"answer":1863},"¿Cuál es la diferencia entre Docker y Docker Compose?","Docker maneja contenedores individuales — un contenedor a la vez. Docker Compose permite definir y levantar múltiples contenedores relacionados (una app, su base de datos, su caché) con un solo archivo YAML y un solo comando. Es la diferencia entre manejar cada pieza por separado y orquestar toda la aplicación como una unidad.",{"question":1865,"answer":1866},"¿Docker Compose sirve para producción?","Para aplicaciones de un solo servidor, sí. Docker Compose es una excelente opción para producción en servidores individuales — levantas todo con un comando, los contenedores se reinician automáticamente y la configuración es reproducible. Para múltiples servidores con alta disponibilidad, necesitas un orquestador como Kubernetes.",{"question":1868,"answer":1869},"¿Puedo usar Docker Compose con bases de datos en producción?","Sí, siempre que configures volúmenes persistentes para los datos. Sin volúmenes, los datos se pierden al recrear el contenedor. Con volúmenes, los datos sobreviven reinicios, actualizaciones y recreaciones del contenedor.",{"question":1871,"answer":1872},"¿Cómo actualizo una aplicación en Docker Compose sin downtime?","Puedes ejecutar docker compose pull para descargar las nuevas imágenes y luego docker compose up -d para recrear solo los contenedores que cambiaron. Los contenedores que no cambiaron siguen corriendo sin interrupción.","/images/blog/docker-compose-guia.jpg","Terminal mostrando un archivo docker-compose.yml con múltiples servicios levantándose en paralelo",{},"/blog/tutorial/docker-compose-guia-completa",{"title":5,"description":1857},"blog/tutorial/docker-compose-guia-completa",[59,88,1880,1881,1852],"contenedores","devops","nWRMKSO1xLiVCKSjgbPJ_56hRSObF2AGeZ_Dsn2UkOo",{"path":1884,"title":1885},"/blog/tutorial/dns-cloudflare-registros","Configurar DNS con Cloudflare — registros esenciales explicados",{"path":1887,"title":1888},"/blog/tutorial/nginx-reverse-proxy-ssl","Configurar Nginx como reverse proxy con SSL gratuito",[1890,1897,1904],{"path":1891,"title":1892,"description":1893,"date":1894,"category":1852,"image":1895,"imageAlt":1896,"readingTime":461},"/blog/tutorial/apis-rest-python-fastapi","Crear APIs REST con Python y FastAPI para integraciones empresariales","Guía paso a paso para construir una API REST profesional con Python y FastAPI que conecte tu ERP, CRM o cualquier sistema con validación, autenticación y documentación automática.","2026-03-04","/images/blog/fastapi-api-rest.jpg","Editor de código mostrando una API FastAPI con documentación Swagger generada automáticamente",{"path":1898,"title":1899,"description":1900,"date":1901,"category":1852,"image":1902,"imageAlt":1903,"readingTime":260},"/blog/tutorial/configurar-firewall-ufw-linux","Configurar firewall en Linux con UFW — reglas esenciales","Guía paso a paso para configurar UFW (Uncomplicated Firewall) en Ubuntu y Debian con las reglas esenciales para proteger servidores de producción.","2026-03-01","/images/blog/ufw-firewall-linux.jpg","Terminal de Linux mostrando reglas de firewall UFW activas protegiendo un servidor de producción",{"path":1905,"title":1906,"description":1907,"date":1908,"category":1852,"image":1909,"imageAlt":1910,"readingTime":439},"/blog/tutorial/traefik-reverse-proxy-docker","Configurar Traefik como reverse proxy para contenedores Docker","Guía paso a paso para instalar Traefik como reverse proxy con descubrimiento automático de contenedores Docker, SSL con Let's Encrypt y dashboard de monitoreo.","2026-02-28","/images/blog/traefik-docker.jpg","Dashboard de Traefik mostrando rutas automáticas hacia múltiples contenedores Docker con SSL activo"]