Introducción
Una versión puede estar correctamente almacenada en S3 mientras la distribución sigue sirviendo una copia anterior. Controla la duración de la caché, observa su reutilización y caducidad e invalida únicamente la ruta de la página actualizada. Conserva la caché de un segundo objeto y la privacidad del origen.
Completa primero el laboratorio de contenido privado de S3. Esta VM independiente proporciona un nuevo bucket privado, OAC, distribución y política correspondiente. No reutiliza recursos de otra VM. Inicialmente, la caché está desactivada y no hay solicitudes de usuarios ni invalidaciones. Los archivos preparados permiten concentrarte en la caché. Observa el estado real en AWS View, arriba, y ejecuta comandos en Terminal, abajo. No necesitas una cuenta personal de AWS ni un dominio público.
Objetivos de certificación
| Certificación | Tarea del examen | Práctica |
|---|---|---|
| Solutions Architect – Associate (SAA-C03) | Tarea 3.4 | Practica la distribución de contenido con CloudFront y el efecto de la duración de la caché en las lecturas del origen. |
Vista general del laboratorio

Observar la reutilización y la caducidad de la caché
En este paso, configura una duración corta para distinguir un acierto de caché de una nueva lectura del origen.
Una caché conserva una copia para solicitudes posteriores. El TTL es su duración en segundos. Cache-Control: max-age del objeto proporciona esa duración; los TTL mínimo y máximo de la distribución la limitan, y el predeterminado se usa cuando el origen no especifica ninguna. Utilizamos estos ajustes normales de la distribución sin crear una política de caché independiente.
Busca la distribución preparada. --query selecciona la que tiene el comentario del laboratorio, y $(...) guarda su ID o dominio en una variable del shell. Mantén Terminal abierto. Examina el bucket de referencia ajeno sin modificarlo:
cd /home/labex/project
DIST_ID=$(aws cloudfront list-distributions \
--query "DistributionList.Items[?Comment=='labex-n03:private-content'].Id | [0]" \
--output text)
DIST_DOMAIN=$(aws cloudfront get-distribution \
--id "$DIST_ID" \
--query Distribution.DomainName \
--output text)
aws s3api list-buckets \
--query 'Buckets[].Name'
Lee la configuración actual y su ETag, el identificador de versión necesario para actualizarla con seguridad. > guarda la salida en un archivo. sed modifica únicamente los dos atributos TTL que valen cero en la configuración preparada; el mínimo sigue en cero. El nuevo máximo permite duraciones mayores después:
aws cloudfront get-distribution-config \
--id "$DIST_ID" \
--query DistributionConfig > current-config.json
ETAG=$(aws cloudfront get-distribution-config \
--id "$DIST_ID" \
--query ETag \
--output text)
sed -e 's/"DefaultTTL": 0/"DefaultTTL": 6/' -e 's/"MaxTTL": 0/"MaxTTL": 3600/' current-config.json > cached-config.json
aws cloudfront update-distribution \
--id "$DIST_ID" \
--if-match "$ETAG" \
--distribution-config file://cached-config.json
aws cloudfront wait distribution-deployed \
--id "$DIST_ID"
Carga la primera versión preparada con una duración de seis segundos. Conserva el tipo de contenido text/html:
aws s3api put-object \
--bucket labex-n03-content \
--key index.html \
--body index.html \
--content-type text/html \
--cache-control 'max-age=6'
curl --include muestra cabeceras y cuerpo. --resolve dirige el nombre real de la distribución al endpoint de esta VM sin cambiar el DNS del sistema. Ejecuta las dos solicitudes seguidas para que la segunda llegue antes de seis segundos:
curl --fail --include --noproxy '*' --resolve "${DIST_DOMAIN}:8082:127.0.0.1" "http://${DIST_DOMAIN}:8082/index.html"
curl --fail --include --noproxy '*' --resolve "${DIST_DOMAIN}:8082:127.0.0.1" "http://${DIST_DOMAIN}:8082/index.html"
La primera muestra X-Cache: Miss from cloudfront y la segunda Hit from cloudfront; ambas devuelven Release one. Un acierto reutiliza los bytes guardados sin leer otra vez el origen. Age indica la edad de la copia; dos solicitudes inmediatas pueden mostrar cero segundos.
sleep 7 deja caducar la copia de seis segundos antes de solicitarla de nuevo:
sleep 7
curl --fail --include --noproxy '*' --resolve "${DIST_DOMAIN}:8082:127.0.0.1" "http://${DIST_DOMAIN}:8082/index.html"
Espera otro fallo de caché con la misma página. La caducidad hace que la siguiente solicitud vuelva al origen; no elimina el objeto de S3. AWS View muestra las solicitudes reales y las lecturas del origen. Ejecuta la comprobación antes de continuar.

Observar una actualización detrás de una copia en caché
En este paso, carga una versión nueva y observa por qué una caché existente todavía devuelve contenido antiguo.
Usa duraciones mayores para observar el fenómeno. Vuelve a cargar la primera página con max-age=900 y carga el objeto independiente stable.txt con max-age=3600. El máximo de 3600 de la distribución permite ambos valores:
aws s3api put-object \
--bucket labex-n03-content \
--key index.html \
--body index.html \
--content-type text/html \
--cache-control 'max-age=900'
aws s3api put-object \
--bucket labex-n03-content \
--key stable.txt \
--body stable.txt \
--content-type text/plain \
--cache-control 'max-age=3600'
Cambiar los metadatos del origen no modifica retroactivamente una respuesta almacenada. Espera a que caduque la copia de seis segundos y solicita las dos rutas para llenar sus cachés:
sleep 7
curl --fail --include --noproxy '*' --resolve "${DIST_DOMAIN}:8082:127.0.0.1" "http://${DIST_DOMAIN}:8082/index.html"
curl --fail --include --noproxy '*' --resolve "${DIST_DOMAIN}:8082:127.0.0.1" "http://${DIST_DOMAIN}:8082/stable.txt"
Ambas solicitudes muestran un fallo de caché y leen el objeto actual del origen. La página ahora incluye Cache-Control: max-age=900. Completa los dos pasos siguientes dentro de esos quince minutos.
El archivo preparado release-two.html contiene la página modificada. Cárgalo con la misma clave de objeto conservando el tipo y la duración. Lee el objeto mediante la CLI de S3 autenticada en origin-release.html para comprobar sus bytes reales:
cat release-two.html
aws s3api put-object \
--bucket labex-n03-content \
--key index.html \
--body release-two.html \
--content-type text/html \
--cache-control 'max-age=900'
aws s3api get-object \
--bucket labex-n03-content \
--key index.html origin-release.html
cat origin-release.html
El origen contiene Release two. Solicita la misma ruta a la distribución:
curl --fail --include --noproxy '*' --resolve "${DIST_DOMAIN}:8082:127.0.0.1" "http://${DIST_DOMAIN}:8082/index.html"
Espera un acierto con Release one. La carga se completó, pero la copia de distribución sigue vigente según su propio TTL. Esto es distinto de un fallo de permisos del origen. Ejecuta la comprobación de la copia anterior.

Invalidar solo la página actualizada
En este paso, haz visible la nueva versión antes de que caduque la copia sin descartar el objeto independiente.
Una invalidación elimina objetos coincidentes de la caché de la distribución. La ruta es una ruta de usuario que empieza por /, no el nombre del bucket ni un archivo local. Usa exactamente /index.html; /* también descartaría innecesariamente el otro objeto.
Crea la solicitud. El atajo --paths de la CLI proporciona el lote y la consulta guarda el ID generado en una variable:
INVALIDATION_ID=$(aws cloudfront create-invalidation \
--distribution-id "$DIST_ID" \
--paths '/index.html' \
--query Invalidation.Id \
--output text)
aws cloudfront wait invalidation-completed \
--distribution-id "$DIST_ID" \
--id "$INVALIDATION_ID"
aws cloudfront get-invalidation \
--distribution-id "$DIST_ID" \
--id "$INVALIDATION_ID" \
--query 'Invalidation.{Status:Status,Paths:InvalidationBatch.Paths.Items}'
Confirma Completed y /index.html. Que el lote esté completo no demuestra por sí solo qué bytes recibe el usuario. Solicita dos veces la página para comprobar el contenido nuevo y su reutilización:
curl --fail --include --noproxy '*' --resolve "${DIST_DOMAIN}:8082:127.0.0.1" "http://${DIST_DOMAIN}:8082/index.html"
curl --fail --include --noproxy '*' --resolve "${DIST_DOMAIN}:8082:127.0.0.1" "http://${DIST_DOMAIN}:8082/index.html"
Espera un fallo con Release two, seguido de un acierto con la misma página nueva. La primera solicitud obtiene los bytes actuales del origen y la segunda reutiliza la copia.
Solicita el objeto independiente y repite la prueba de acceso anónimo directo al origen:
curl --fail --include --noproxy '*' --resolve "${DIST_DOMAIN}:8082:127.0.0.1" "http://${DIST_DOMAIN}:8082/stable.txt"
curl --noproxy '*' --output /dev/null --write-out 'Anonymous origin: HTTP %{http_code}\n' http://127.0.0.1:5000/labex-n03-content/index.html
stable.txt debe seguir dando un acierto con el contenido original, sin otra lectura del origen. S3 anónimo debe seguir respondiendo HTTP 403. Invalidar cambia la caché, no los permisos del origen. Ejecuta la comprobación de actualización dirigida.

Eliminar solo tus recursos de distribución
En este paso, desactiva y elimina primero la distribución, después OAC y el contenido de S3. Conserva el bucket de referencia.
CloudFront usa ETag como token de versión de la configuración. Obtén la configuración y el ETag actuales; no inventes el token.
Antes de eliminar la distribución, lee su ID de OAC. La variable conserva el control exacto que debes limpiar:
OAC_ID=$(aws cloudfront get-distribution-config \
--id "$DIST_ID" \
--query 'DistributionConfig.Origins.Items[0].OriginAccessControlId' \
--output text)
Guarda ahora la configuración actual y obtiene su ETag:
aws cloudfront get-distribution-config \
--id "$DIST_ID" \
--query DistributionConfig \
--output json > distribution-current.json
DIST_ETAG=$(aws cloudfront get-distribution-config \
--id "$DIST_ID" \
--query ETag \
--output text)
En la configuración actual de este laboratorio, Enabled de la distribución es el único atributo de ese nombre que vale true. Esta sustitución normal con sed crea una copia desactivada conservando los ajustes del origen:
sed 's/"Enabled": true/"Enabled": false/' distribution-current.json > distribution-disabled.json
aws cloudfront update-distribution \
--id "$DIST_ID" \
--if-match "$DIST_ETAG" \
--distribution-config file://distribution-disabled.json
Espera a que se despliegue la configuración desactivada. La propagación de AWS puede tardar; aquí no medimos la latencia de despliegue mundial:
aws cloudfront wait distribution-deployed \
--id "$DIST_ID"
La actualización cambia el ETag. Lee el token más reciente antes de eliminar la distribución desactivada:
DIST_ETAG=$(aws cloudfront get-distribution-config \
--id "$DIST_ID" \
--query ETag \
--output text)
aws cloudfront delete-distribution \
--id "$DIST_ID" \
--if-match "$DIST_ETAG"
Elimina el OAC usando su propio ETag. El ID de distribución y el de OAC identifican recursos diferentes:
OAC_ETAG=$(aws cloudfront get-origin-access-control \
--id "$OAC_ID" \
--query ETag \
--output text)
aws cloudfront delete-origin-access-control \
--id "$OAC_ID" \
--if-match "$OAC_ETAG"
Elimina únicamente los dos objetos del laboratorio y su bucket:
aws s3api delete-object \
--bucket labex-n03-content \
--key index.html
aws s3api delete-object \
--bucket labex-n03-content \
--key stable.txt
aws s3api delete-bucket \
--bucket labex-n03-content
aws s3api list-buckets \
--query 'Buckets[].Name'
El bucket de referencia debe permanecer y el de contenido debe haber desaparecido. AWS View debe mostrar ninguna distribución de contenido y solo el objeto de referencia. Ejecuta la comprobación de limpieza. Una solicitud de API fallida no demuestra una eliminación.

Resumen
Configuraste los límites TTL y Cache-Control del objeto, observaste que un acierto no aumenta las lecturas del origen y dejaste caducar una copia breve. Comprobaste que cargar una nueva versión en el origen no sustituye una copia de usuario todavía vigente. Invalidar la ruta exacta obtuvo la página nueva conservando la caché independiente y el origen privado. Después eliminaste únicamente tus recursos. Para versiones frecuentes, los nombres de objeto con versión también permiten seleccionar contenido nuevo; aquí practicaste la actualización de una ruta existente.



