상현에 하루하루
All 개발자의 하루

docker-swarm에서 Traefik으로 운영하는 WordPress에 Redis를 적용해보자

( 업데이트: )

워드프레스를 운영하면서 몇가지 불편한점들이 있었다.

워드프레스를 엔드 유저에게 서비스하는 것은 워드프레스에서 정적으로 배포하는 부분을 캐싱하는 것으로 만족스럽게 사용하고있었다. 나는 워드프레스 캐싱을 WP Rocket으로 하고있다.

이 부분에 대해서는 만족스럽게 사용하고있었지만 이제 운영하는 관리자 입장에서 로그인을 하면 모든 페이지가 캐싱이 되지않게 로드한다. 그래서 이때 게시글을 확인하거나 관리자 대시보드에서 답답함을 느끼게 된다. 그럼 이 것을 어떻게 해결할 수 있을까? 고민을 하다가 쿼리 요청에 대한 것을 캐싱하면 만족스러운 성능이 나오지 않을까 생각을 했다.

기본적으로 필자가 구성하는 모든 서비스, 애플리케이션은 Docker를 기반으로 찾고 실행한다

TL;DR

워드프레스 공식 이미지는 Apache + WordPress로 wp-config.php의 Redis 호스트, 포트를 설정해주면 해당 Redis를 기능을 사용하게된다.

/* Redis */
define('WP_REDIS_HOST', getenv_docker('WORDPRESS_REDIS_HOST', 'redis'));
define('WP_REDIS_PORT', getenv_docker('WORDPRESS_REDIS_PORT', 6379));

해당 코드를 wp-config.php 파일에서 /* That's all, stop editing! Happy publishing. */ 줄 이전에 위 예제 코드를 추가해주면 된다.

docker 이미지가 구성되면서 wp-config.php파일에 작성할 수 없기 때문에 dokcer-compose.yaml에서 환경변수로 주입해주면 된다.

services:
  wordpress:
    image: ghcr.io/hansanghyeon/wordpress-redis:php8.0-apache-redis
    restart: always
	  ports:
		- 80:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wp
      WORDPRESS_DB_PASSWORD: wp
      WORDPRESS_DB_NAME: wp
      WORDPRESS_CONFIG_EXTRA: |
        /* Redis */
        define('WP_REDIS_HOST', getenv_docker('WORDPRESS_REDIS_HOST', 'WORK-sampyo_redis'));
        define('WP_REDIS_PORT', getenv_docker('WORDPRESS_REDIS_PORT', 6379));
    volumes:
      - wordpress:/var/www/html
  db:
    image: mariadb
    restart: always
    environment:
      MYSQL_DATABASE: wp
      MYSQL_USER: wp
      MYSQL_PASSWORD: wp
      MYSQL_RANDOM_ROOT_PASSWORD: "1"
    volumes:
      - db:/var/lib/mysql
  redis:
    image: redis:latest
    volumes:
      - redis:/data
volumes:
  redis:

이렇게 설정하면 워드프레스 컨테이너가 Redis를 사용할 수 있게된다. (Php5-redis를 사용)

Redis란?

Redis란 빠른 오픈 소스인 메모리 키 값 데이터 구조 스토어입니다. Redis는 다양한 인 메모리 데이터 구조 집합을 제공하므로 다양한 사용자 정의 애플리케이션을 손쉽게 생성할 수 있습니다. 주요 Redis 사용사례로는 캐싱, 세션 관리, pub/sub 및 순위표를 들 수 있습니다. Redis 현재 가장 있기 있는 키 값 스토어로서, BSD 라이선스가 있고, 최적화된 C 코드로 작성되었으며, 다양한 개발 언어를 지원합니다. Redis는 Remote Dictionary Server의 약어입니다.

aws: https://aws.amazon.com/ko/elasticache/what-is-redis/

Redis 적용을 검색해보자

Redis를 검색해보면 NGINX + Redis의 예제들이 대표적으로 나온다. 그래서 웹서버는 NGINX로 구성해야하는구나 판단을 했다. 그런데 필자의 대부분의 WordPress 애플리케이션들은 기본 이미지를 사용하기 때문에 Apache + WordPress 스택으로 구성되어있다. 그래서 어떻게 해야할까 고민이 들었다.

일단 NGINX + PHP-FPM + WordPress를 구성해보자.

NGINX + PHP-FPM + WordPress

GitHub – Hansanghyeon/wordpress-nginx-phpfpm: WordPress PHP-FPM & Nginx dokcer-compose example

여기서 핵심은 NGINX로 오는 트래픽을 업스트립으로 PHP-FPM으로 보내는 것이다. 그렇게 워드프레스 컨테이너를 사용!

그렇다면? 어떻게 Redis

Github – Hansanghyeon/wordpress-redis at v1.0.0

NGINX + PHP-FPM에서 Redis를 사용하려면 따로 Redis 적용을 위한 모듈들을 설치해야한다.

여기서 wordpress:php8.0-fpm 이미지를 베이스로 dockerizing한다.

FROM wordpress:php8.0-fpm

RUN apt-get update && apt-get install -y \
  libicu-dev \
  libmcrypt-dev \
  libmagickwand-dev \
  libsodium-dev \₩₩₩
  libzip-dev \
  --no-install-recommends && rm -r /var/lib/apt/lists/* && pecl install redis-5.3.4 imagick-3.5.1 libsodium-2.0.21 && docker-php-ext-enable redis imagick sodium && docker-php-ext-install -j$(nproc) exif gettext intl sockets zip

위 만들어진 이미지를 가지고 NGINX와 PHP-FPM(Redis)이미지를 가지고 정상적으로 로컬에서 작동하는 것을 확인했다.

그런데? 문제가 생겼다.

Traefik + docker-swarm / NGINX + wordpress:php8.0-fpm (Redis) 적용하기

이상하게 docker-compose up -d로 구성해서 로컬에서 적상작동을 확인한 서비스를 Traefik으로 테스트 배포를 해봤는데 http에 대한 요청이 정상적으로 https로 넘어가지 않는 문제가 생겼다.

왜 그럴까 다른 모든 애플리케이션은 Traefik의 http -> https 리다이렉트 미들웨어로 문제없이 사용하였는데

일단 이렇게 구성을하면 https로 요청이가지않아서 wp-config.php 파일이 만들어지지 않는 것을 확인하였다.

내가 커스텀하게만든 이미지가 아니라 기본이미지로 만들어도 동일한 문제가 발생했다.

이 문제 때문에 어떻게 해야할지 감이 잡히지 않아서 다시 처음부터 점검하기로했다.

다시 처음부터, 왜 apache가 아니라? NGINX로 만들어서 이렇게 많은 요구사항을 충족해야할까?

Apache와 NGINX중 어떤 것을 선택해야할지 정리 해봤다.

워드프레스 웹서버 선택 nginx or Apache

성능상 우위는 NGINX라서 Apache에 대한 자료가 없는 것인가?

왜 Apache에서는 Redis를 구성할 수 없을까? 왜 이것에 대한 예제들은 없지?

정확하게 Apache Redis에 대한 예제를 살펴볼 수 없으니까 정말 답답한 노릇이었다.

그래서 너무 검색에만 의존하지 않으려고 그냥 시도를 해봤다. 그리고 안된다면 Apache에서 Redis를 사용할수 있도록 어떤 조치를 해야할지 찾아봐야겠다 계획을 가지고 무작정 직진

된다, 아주 잘된다 이게 무슨일일까?

WordPress에 Redis를 적용하기 까지 삽질을 많이했는데 결국 기존 서비스에서 Redis만 붙이면 되는 것이었다. 그래도 다행히 여러 수고로움없이 문제를 해결했다.

  • docker
  • docker-swarm
  • Traefik (http > https 미들웨어)
  • wordpress:php8.0
  • Redis

Redis는 공용으로 사용하지 말고 단독으로

WordPress를 여러개 배포해서 사용하고있는데 이것을 각각 모든 서비스의 다른 DB 컨테이너를 사용하는 것이아닌 단일 DB 컨테이너에서 사용하고있었다. 그래서 Redis도 동일하게 사용해야지 생각하고 동일하게 적용하였더니 각각 모든 워드프레스에서 같은 류의 key - value로 연결되어있어서 의도하지 않은 다른 워드프레스의 캐싱을 불러오게 된다는 것을 알게되었다.

그러니까 각 서비스에 단독으로 Redis를 붙여서 사용하자

이 내용 또한 내가 잘못 이해한 것이다

Redis에 Database를 선택하는데 Redis Object Cache 플러그인은 기본값으로 0번의 DB를 사용한다.

DB의 번호를 선택하는 방식으로 한다면 한개의 Redis에서 다양한 서비스를 연결해서 사용할 수 있을 것같다.

지금은 docker-compose에서 해당 Redis의 DB를 선택할 수 없기때문에 기존에 하던대로 1개의 Redis를 단독으로 연결 시키려한다.

🚨 됬는대 안된다? 그리고 원인 해결

3~4개의 docker-compose로 만들어진 워드프레스를 대상으로 테스트를 해보니?

Redis Object Cache 플러그인이 활성화 되기 위해서는 아래 3가지중 한가지라도 필요했다

  • Php5-redis
  • Predis
  • Credis

블로그에서는 Predis가 설치가되어있어서 내가 생각했던대로 활성화가 된것이 아니었다.

플러그인 홈페이지에서도 Predis보다는 Php5-redis로 설치를 권유하고 pro버전에서도 Php5-redis로 필수로 요청하는 것을 보고 합리적으로 Php5-redis로 교체해야겠다 생각했고 왜 되는 것일까의 의문이 풀려서 해당 docker 이미지를 만들기로 했다.

FROM wordpress:php8.0-apache

RUN apt-get update && pecl install redis-5.3.4 php5-redis && docker-php-ext-enable redis

Hansanghyeon/wordpress-redis at php8.0-apache-redis