Tu propio StackOverflow con Apache Answer.
Answer te permite montar tu propia plataforma de preguntas y respuestas en tu servidor. Aprende con nosotros a alojarlo en casa o en la oficina con Podman.
Llevo eones prometiendo el artículo del servidor multimedia. Parece que subestimé la cantidad de información que uno da por sentada al momento de escribir un artículo en un blog.
Para no dejar este lugar muerto por meses como las veces anteriores, me decidí a sacar este mini-tutorial para ustedes de como desplegar Apache Answer en su servidor local o del trabajo.
Answer es una plataforma o herramienta de búsqueda y procesamiento de preguntas (y sus respuestas) para equipos pequeños de desarrollo o de TI. Como Answer se enfoca en la privacidad y seguridad, es ideal para implementaciones en servidores de nicho o en entornos empresariales donde las políticas de privacidad son más estrictas o donde no deseas compartir los detalles de tu infraestructura con el mundo.
Para no perder la práctica en Podman, te traigo este artículo. Trataré de incluir variaciones en el despliegue con podman y esta vez no limitaré el contenido 😄. Recursos gratis para todos.
¿Para qué querría esto? 🤔
Existen distintas razones por las cuales querrías tener una instancia de Answer a tu disposición:
- Si lideras o formas parte de una pequeña comunidad de desarrolladores: Answer es perfecto para comunidades pequeñas de varios desarrolladores que necesiten compartir conocimientos técnicos muy específicos. Por ejemplo, detalles o dudas de infraestructura, despliegues, prácticas de código. Etc.
- Soporte técnico interno: Las empresas pueden implementar Answer para que los empleados compartan soluciones y respondan preguntas internas.
- Educación y formación: Las instituciones educativas pueden utilizar Answer como una herramienta de colaboración para estudiantes y profesores.
¿Por qué no una wiki u otra forma de documentación interna? 🤓
Esta elección en tu entorno dependerá de varios factores. Una wiki interna puede ayudarte a documentar de forma extensiva procesos, infraestructura y detalles extensos de tu entorno, sin embargo, la información se presenta de forma general y podría no cubrir casos de desarrollo nuevos, preguntas de uso o la implementación completa.
Answer te será útil si buscas:
- Interacción activa
- El formato de preguntas y respuestas permite interacción activa entre usuarios. Con dichas preguntas y respuestas teniendo una respuesta más inmediata y más “al grano”. A diferencia de una Wiki, donde sería necesario estructurar la información para que sea más accesible.
- Enfoque en problemas específicos
- Answer se centra en resolver problemas específicos y proporcionar soluciones concretas.
- Una wiki interna puede ser más general y no siempre abordar los problemas específicos que enfrentan los usuarios.
- Privacidad y seguridad
- Answer se preocupa por la privacidad y la seguridad de los datos. No rastrea ni comparte información personal.
- En una wiki interna, la seguridad y la privacidad pueden ser más difíciles de garantizar. Especialmente si se trata de un SaaS/PaaS o de algún software antiguo que no recibe actualizaciones frecuentes.
- Facilidad de uso
- Sabes usar StackOverflow, sabes usar Answer.
- Una wiki interna puede requerir más tiempo para navegar y encontrar la información deseada.
Usarlo o no dependerá de tu criterio y tus necesidades.
Requerimientos 🧑🏫
Para seguir este tutorial asumiré que cumples con los siguientes requisitos:
Un VPS o un servidor donde desplegar Answer 💻
Como alternativa, también podrías usar algún PaaS como Fly.io o alojarlo en tu computadora.
Podman 🦭
Puedes usar Docker y Docker Compose. Pero en este blog solo usamos Podman 😄
Opcional: Una base de datos PostgreSQL 🐘
Necesitarás de una base de datos adicional en caso de que desees desplegar de forma distinta Answer. Si no la tienes, no te preocupes. Aquí aprenderás como levantar Answer con PostgreSQL.
Un usuario sin privilegios en Gnu/Linux para el despliegue 🤖
Si pretendes usar este contenedor de forma rootless
. Deberás crear un usuario para el mismo, te recomiendo algo como adduser answer
o adduser localoverflow
para tu servidor. No te olvides de configurar los permisos de los directorios que necesitarás montar como volúmenes.
Conocimientos básicos de SQL 🧠
No soy experto en bases de datos. Aun así, asumiré que ya has desplegado una BD en el pasado y conoces suficiente de consultas SQL para crear una mísera base de datos.
Despliegue con Podman 🦭
Antes de desplegar nada utilizando Podman debemos preparar nuestro entorno de despliegue. Para esto vamos a descargar las imágenes necesarias y configurar los directorios correspondientes.
Descargar imagenes de Podman/Docker ⬇️
Si ya tienes Docker Hub configurado como registro en podman simplemente puedes ejecutar la siguiente orden:
En caso de que no tengas (y no quieras configurar Docker Hub) como registro en Podman, puedes escribir el “nombre completo” de la imagen, es decir, incluyendo el registro:
- Para descargar Answer solamente (SQLite):
podman pull docker.io/apache/answer:latest
- Para descargar PostgreSQL en su última versión en Alpine Linux:
podman pull docker.io/postgres:alpine
- Si deseas utilizar PostgreSQL con Debian en su lugar puedes ejecutar:
podman pull docker.io/postgres:bookworm
- Si deseas utilizar PostgreSQL con Debian en su lugar puedes ejecutar:
¿Puedes hacer algo que me ahorre esos pasos?
No, mentira 😆. Aquí hay un pequeño script que hice tratando de ahorrarme los pasos de este tutorial, esto que diré se pasa todo el propósito de podman por el arco del triunfo, pero en mi máquina funciona. Puedes utilizar este script como guía o como “instalador” no oficial de las imagenes.
Para comprobar que descargaste las imagenes correctas, puedes ejecutar podman images
si seguiste bien los pasos o todo te salió bien, deberías ver una salida en tu terminal similar a esta:
Si estás usando Podman Desktop, en la pestaña de “images” podrás ver tus imagenes descargadas:
Crear directorios de datos 📁
Ahora, necesitarás crear los directorios donde se almacenen los datos. Lamentablemente, mi flojera no me dio para hacer un script separado o incluirlo en el script original. Además de que no sé en qué directorio del sistema de archivos deseas hacer esto. En mi caso trabajaré sobre /home/localoverflow
, pero tú puedes utilizar el directorio que más te guste.
Para Answer 💭
Answer solo requiere de un directorio para almacenar la información. Este directorio en la imagen es /data
, aquí te presento algunas rutas que podrías utilizar, asegúrate de que tienes permisos de lectura y escritura en el directorio que vayas a elegir:
/opt/answer/data
/home/localoverflow/answer/data
/home/localoverflow/.answer/data
/home/localoverflow/.local/share/answer/answer-data
Realmente puedes utilizar tu directorio favorito.
Para PostgreSQL 🐘
PostgreSQL maneja un caso similar, solo que, en esta ocasión, el directorio dentro de la imagen es /var/lib/postgresql/data
. Espero no tener que repetir lo mismo una tercera vez:
/opt/answer/postgres/data
/home/localoverflow/answer/postgres/data
/home/localoverflow/.answer/postgres/data
/home/localoverflow/.local/share/postgres/data
/home/localoverflow/.answer
. Ajusta los pods y los comandos a los directorios que deseas usar.Desplegar con contenedor standalone + SQLite3 👨💻
El despliegue standalone es el más sencillo de todos, solo debemos montar el directorio de datos para Answer que creamos anteriormente desde el comando de podman.
Vamos a ejecutar nuestro despliegue standalone con el siguiente comando:
Si tu contenedor se creó correctamente, verás en la salida de la consola el identificador del contenedor:
podman run -d \
-p 9080:80 \
-v /home/localoverflow/.answer/data:/data \
--name="answer-standalone" \
--restart=always \
--label io.containers.autoupdate=registry docker.io/apache/answer:latest
0ff0903ded67cf0711f5f0ce71bdb2f044d6605919c6c22fcc5bb96f0b1a51f7
Puedes comprobar que tu contenedor se está ejecutando con el comando podman ps
:
podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0ff0903ded67 docker.io/apache/answer:latest 2 minutes ago Up 2 minutes 0.0.0.0:9080->80/tcp answer-standalone
Si estás usando Podman Desktop podrás ver tu contenedor en ejecución en la pestaña “containers”:
Vamos a ingresar a la dirección que le colocamos a Answer para configurarlo
- Ingresa a
localhost:9080
,127.0.0.1:9080
o al0.0.0.0:9080
. Si ves la siguiente pantalla en tu navegador, felicidades, lo lograste:
- Selecciona el idioma que más te guste o el que prefieras. El número que indica la lista es el porcentaje de texto traducido a ese idioma presente en Answer.
- Selecciona en la lista de bases de datos la opción
SQLite
y deja la opciónDatabase file
con su valor por defecto:
- Si todo salió bien, el instalador te reportará que pudo crear el archivo
config.yaml
de manera satisfactoria:
- Configura los detalles de tu instancia de Answer:
Las opciones que te presentará Answer son las siguientes:
- Site Name: El título del sitio que se mostrará en el navegador.
- Site URL: La URL del sitio. Si vas a desplegar esto bajo un dominio
- Contact email: La dirección de correo electrónico de contacto en caso de que tus usuarios necesiten asistencia técnica con el sitio.
- Private: Si los visitantes del sitio necesitan estar registrados para explorar las preguntas y respuestas del mismo.
- Admin Account
- Name: Username del administrador
- Password: Contraseña del administrador (Te recomiendo generarla con un gestor de contraseñas como KeePassXC o Bitwarden)
- Email: Correo electrónico para iniciar sesión con la cuenta de administrador.
- Si configuraste correctamente tu instancia de Answer podrás ver la siguiente pantalla:
Cuando presiones el botón azul con el texto “Done” serás redirigido al sitio de Login:
Ingresa con las credenciales que acabas de configurar. Y listo. Disfruta de tu nueva instancia de Answer.
Desplegar con contenedor standalone + PostgreSQL 🦭🐘
Los pasos para desplegar Answer junto con PostgreSQL en contenedores son muy similares. La creación del contenedor de Answer es exactamente igual:
Toca levantar el contenedor de PostgreSQL, si ya tienes la imagen de Podman descargada, puedes ejecutar el siguiente comando:
Probar la conexión a la base de datos 📚
Puedes revisar si tu contenedor está vivo usando el comando podman ps
, revisar en podman desktop o si tienes un cliente gráfico de bases de datos puedes utilizarlo para revisar la conexión a la misma.
Si deseas cambiar el nombre de la base de datos creada por defecto, añade la variable de entornoPOSTGRES_DB
. De no hacerlo el valor dePOSTGRES_USER
será utilizado para esa base de datos.
Una vez comprobada la conexión a nuesta base de datos, es momento de configurar Answer. Los pasos de configuración son exactamente iguales, con la diferencia en la configuración de la BD. Omitiré la serie de pasos antes y después de la BD.
En mi caso hice una nueva base de datos para el despliegue con el nombre answer
:
SELECT 'CREATE DATABASE answer'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'answer')\gexec
- En la sección de configuración de base de datos, deberás colocar los detalles de la DB PGSQL que acabas de crear en podman:
En mi caso quedó así:
localhost
porque estoy idiota para las redes y olvidé que podía usar la IP de Docker. Si tu conexión a la BD es correcta, el resto de pantallas será el mismo:
No hay más pasos que modificar de aquí en adelante, es un despropósito repetir las instrucciones si no cambia algo en el proceso.
Despliegue con Podman en un Pod 🦭📦
En caso de que necesites orquestar tus contenedores de Answer y su respectiva base de datos o que, en un futuro, necesites migrarlo a Kubernetes, podemos desplegarlo directamente en un pod.
Antes de usar cualquiera de las variaciones presentadas aquí, deberás crear un pod primero:
- Comando para Pod de Answer Standalone:
podman pod create --name AnswerStandalone -p 9080:80
- Comando para Pod de Answer + PostgreSQL:
podman pod create --name AnswerPostgres -p 5432:5432 -p 9080:80
Para revisar tu configuración de Pods o que se hayan creado correctamente puedes ejecutar el comando podman pod ps
:
podman pod ps
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
f5fbb64a5164 AnswerStandalone Created 2 minutes ago d0f8e296d69f 1
Si estás usando Podman Desktop puedes verlo en esta pestaña:
Pod Standalone 🧑🔧
Los pasos son similares al despliegue con podman standalone, solo que, ahora, la orden de creación del contenedor no necesita que le digamos qué puertos exponer:
podman run -d \
--pod AnswerStandalone \
-v /home/localoverflow/.answer/data:/data \
--name="answer-standalone" \
--restart=always \
--label io.containers.autoupdate=registry docker.io/apache/answer:latest
Podemos ver si nuestro contenedor se agregó correctamente con el comando podman pod stats AnswerStandalone
:
POD CID NAME CPU % MEM USAGE/ LIMIT MEM % NET IO BLOCK IO PIDS
f5fbb64a5164 1866beae3871 answer-standalone 0.45% 100.9MB / 16.52GB 0.61% 268B / 430B -- / -- 10
f5fbb64a5164 d0f8e296d69f f5fbb64a5164-infra 0.01% 40.96kB / 16.52GB 0.00% 268B / 430B -- / -- 1
O desde Podman Desktop:
Vamos a generar un .yml para este pod de Kubernetes con podman generate kube AnswerStandalone > answer-standalone-pod.yml
.
Puedes descargarlo aquí:
Para ejecutar el pod solo ve al directorio donde se encuentra el archivo .yml
y ejecuta el comando:
~$ podman play kube ./answer-standalone-pod.yml
Pod PostgreSQL 📦🐘
Similar al pod de Answer Standalone, podemos generar un pod de Podman con Answer y PostgreSQL para "llevarnos" nuestro despliegue a donde queramos. Vamos a repetir el comando para crear el pod que necesitamos:
Vamos a comprobarlo:
Con podman pod ps
:
~$ podman pod ps
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
f1157d0cfdc4 AnswerPostgres Created About a minute ago b0826ce0dc76 1
O desde podman desktop:
Aunque la imagen se vea diferente a la anterior, no te preocupes, la diferencia es que este pod está vacío y todos sus contenedores detenidos. Arreglaremos eso pronto. Por el momento es suficiente saber que nuestro pod de creó correctamente.
Vamos a agregar el contenedor de Answer al pod que acabamos de crear:
Ahora hacemos lo mismo con PostgreSQL:
Comprobamos que los contenedores se encuentran en ejecución con podman pod stats AnswerPostgres
~$ POD CID NAME CPU % MEM USAGE/ LIMIT MEM % NET IO BLOCK IO PIDS
f1157d0cfdc4 b0826ce0dc76 f1157d0cfdc4-infra 0.01% 36.86kB / 16.52GB 0.00% 134B / 430B -- / -- 1
f1157d0cfdc4 2d351afdd02a answer-standalone 0.57% 98.88MB / 16.52GB 0.60% 134B / 430B -- / -- 8
f1157d0cfdc4 56d3655878fb pgsql-pod 0.36% 3.887MB / 16.52GB 0.02% 134B / 430B -- / -- 6
Y en Podman Desktop ahora podemos ver esto:
Puedes repetir los pasos de PostgreSQL en este tipo de despliegue. En la configuración de base de datos podrás usar ahora si la dirección 0.0.0.0
para conectar Answer a la base de datos.
Podemos generar un archivo de kubernetes con un Pod también, el comando es igual al de un contenedor standalone: podman generate kube AnswerPostgres > answer-postgres-pod.yml
Puedes descargarlo aquí:
Integrar con systemd + actualizaciones ⚙️⬆️
Contenedor standalone
Para generar un servicio de systemd en nuestro usuario localoverflow
con el contenedor answer-standalone
generado (pero no en ejecución), ejecuta los siguientes comandos:
mkdir -p ~/.config/systemd/user/
podman generate systemd --new answer-standalone > ~/.config/systemd/user/answer-container.service
Entra al directorio a explorar tu unidad de systemd generada por Podman. Debería verse similar a esto:
# container-4fe6da067758a81050bb9e2c515d767d47cb4dfce7b0ca129c52d99ac8bb313e.service
# autogenerated by Podman 4.5.1
[Unit]
Description=Podman container-4fe6da067758a81050bb9e2c515d767d47cb4dfce7b0ca129c52d99ac8bb313e.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
TimeoutStopSec=70
ExecStart=/usr/bin/podman run \
--cidfile=%t/%n.ctr-id \
--cgroups=no-conmon \
--rm \
--sdnotify=conmon \
--replace \
-d \
-p 9080:80 \
-v /home/localoverflow/.answer/data:/data \
--name=answer-standalone \
--label io.containers.autoupdate=registry docker.io/apache/answer:latest
ExecStop=/usr/bin/podman stop \
--ignore -t 10 \
--cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm \
-f \
--ignore -t 10 \
--cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all
[Install]
WantedBy=default.target
El contenedor al estar configurado con la opción: --label io.containers.autoupdate=registry
es fácilmente actualizable ejecutando el siguiente comando:
podman auto-update
Trying to pull docker.io/apache/answer:latest...
Getting image source signatures
Copying blob 4fe6da067758 done
Copying config e2c515d767d4 done
Writing manifest to image destination
Storing signatures
UNIT CONTAINER IMAGE POLICY UPDATED
answer-container.service dfce7b0ca129 (enable-sysadmin) docker.io/apache/answer:latest registry true
Pod (de cualquier tipo)
Me sorprende que hayas llegado hasta aquí sin amar a Podman, similar al artículo anterior, podemos usar sus poderes para generar los servicios de systemd necesarios para nuestro usuario rootless de Podman, si no recuerdas el comando, es:
~$ cd ~/.config/systemd/user/ && podman generate systemd --files --name AnswerPostgres
La salida de este comando (en mi caso) se ve así:
/home/localoverflow/.config/systemd/user/pod-AnswerPostgres.service
/home/localoverflow/.config/systemd/user/container-answer-standalone.service
/home/localoverflow/.config/systemd/user/container-pgsql-pod.service
Detén los contenedores que tengas en ejecución o detén todo el pod que creaste con podman pod stop AnswerPostgres
(PERO NO LO ELIMINES).
Una vez hecho eso podrás ejecutar systemctl enable --now pod-AnswerPostgres
Conclusión ✍️
Maldita sea, qué rico es Podman para levantar aplicaciones a lo desgraciado en servidores.
Yo mismo tengo una instancia de Answer personal, para aquellos problemas que no vale la pena documentar en este blog y que, estoy seguro, me voy a topar más de una vez con ellos:
Las capacidades de Podman no se limitan a aplicaciones profesionales, puedes comenzar a utilizarlo como parte de tus procesos de desarrollo y deploy en producción. Solo debes perder el miedo a experimentar por tu cuenta. Dime ¿qué opinas de todo esto? ¿más tutoriales así te animarían a usar Podman en tu trabajo o en tu vida diaria como informático?
Siéntete libre de dejarme tu feedback en las redes sociales de La Esquina Gris, apreciaré mucho tus comentarios 👍
¿No hay una versión con MariaDB?
Mentira de nuevo 😆. Me pareció innecesario crear un apartado con MySQL/MariaDB ya que las instrucciones son 99.98% parecidas a las de PostgreSQL y las únicas diferencias son el puerto y la imagen de Docker. Puedes replicar los pasos de MariaDB intuyendo las instrucciones de PGSQL.