feat: architecture diagram and operations explanation

This commit is contained in:
Payton Bates committed 2026-10-15 22:26:18 -04:00
1 parent 1d7c528795
commit 89359a6ce3
3 files changed
+105 -4

No files matched your search

+43 -4
View File
@@ -374,9 +374,16 @@ not confirmed. Payton has taken ownership of the remaining Gitea tasks.
The initial main push is not counted as a reviewed PR. The initial main push is not counted as a reviewed PR.
\section{Architecture and Operation} \section{Architecture and Operation}
The current private initialization path is shown in Figure~\ref{Figure:GiteaArchitecture} shows the deployed request and data paths.
Figure~\ref{Figure:GiteaInitialPath}. Payton will add a final deployment diagram \begin{figure}[htbp]
showing browser HTTPS to Caddy and private forwarding to Gitea. \centering
\resizebox{\linewidth}{!}{\input{figures/devopsGiteaFoundation/giteaArchitecture}}
\caption{October 15: deployed architecture. The security group admits 443 and 80 from any source and 22 only from approved team addresses. Caddy is the only container publishing host ports; Gitea, the Color Buttons app, and both data volumes are private.}
\label{Figure:GiteaArchitecture}
\end{figure}
The initial October 12 access path, before Caddy was deployed, is kept for
reference in Figure~\ref{Figure:GiteaInitialPath}.
\begin{figure}[htbp] \begin{figure}[htbp]
\centering \centering
\fbox{\parbox{0.92\linewidth}{\centering \fbox{\parbox{0.92\linewidth}{\centering
@@ -387,7 +394,7 @@ $\downarrow$ EC2: 100.49.80.94\\
EC2 loopback:3000 to Gitea container:3000\\ EC2 loopback:3000 to Gitea container:3000\\
$\downarrow$ persistent named volume\\ $\downarrow$ persistent named volume\\
\texttt{inviscid\_gitea\_data}: repositories, SQLite, configuration}} \texttt{inviscid\_gitea\_data}: repositories, SQLite, configuration}}
\caption{Initial SSH-tunnel access path. Caddy and hostname-based HTTPS are not yet verified.} \caption{October 12: initial SSH-tunnel-only access path, before Caddy and hostname-based HTTPS were deployed.}
\label{Figure:GiteaInitialPath} \label{Figure:GiteaInitialPath}
\end{figure} \end{figure}
@@ -406,8 +413,40 @@ The following are operational commands, not additional claimed test results:
cd ~/gitea cd ~/gitea
sudo docker compose ps sudo docker compose ps
sudo docker compose logs --tail=40 gitea sudo docker compose logs --tail=40 gitea
sudo docker compose logs --tail=40 caddy
sudo docker compose restart gitea sudo docker compose restart gitea
sudo docker compose restart caddy
\end{minted} \end{minted}
\paragraph{Where data lives.} Repositories, attachments, Gitea configuration,
and the SQLite database (\path{/data/gitea/gitea.db}) live in the named volume
\texttt{inviscid\_gitea\_data}. Certificates and the ACME account live in
\texttt{inviscid\_caddy\_data} (with \texttt{inviscid\_caddy\_config}). All
three volumes are on the instance's EBS disk, outside the disposable container
layers. Deployment files are versioned in \path{docker/gitea/} of the repository.
\paragraph{Public and private interfaces.} Public: TCP 443 (HTTPS to Caddy) and
TCP 80 (redirect to HTTPS, ACME validation, and the Color Buttons app by IP),
both from any source. Restricted: TCP 22 (administrative SSH) from approved team
addresses only. Private: Gitea's port 3000 (reachable only on the Compose network
and EC2 loopback), the Color Buttons container's port 3000, Caddy's admin port
2019, and the SQLite file, which has no network port.
\paragraph{Troubleshooting.} If \url{https://git.inviscid.dev} fails, check in
order: (1) \texttt{docker compose ps} shows both services running; (2) the Caddy
log shows no certificate or upstream errors; (3) the Gitea log shows it listening
on port 3000; (4) \texttt{curl -I http://127.0.0.1:3000/} on EC2 returns 200,
which isolates Gitea from Caddy; (5) DNS still resolves to the Elastic IP and the
security group still admits 443. Restarting one service leaves its volume intact.
\paragraph{Persistence test versus backup/restore.} The container-replacement
test shows that data survives when the Gitea \emph{container} is discarded,
because the named volume is reattached. It does not protect against loss of the
volume, the EBS disk, or the instance, and it creates no copy elsewhere. A
backup/restore test would copy the volume and database to separate storage and
prove recovery into a different instance; that optional exercise
(Section~2.8 of the assignment) was not performed.
Closing a workstation tunnel does not stop Gitea on EC2. Reconnect the tunnel Closing a workstation tunnel does not stop Gitea on EC2. Reconnect the tunnel
for browser access. Container replacement should retain the named volume; for browser access. Container replacement should retain the named volume;
never delete that volume as part of the persistence check. Before destructive never delete that volume as part of the persistence check. Before destructive
+2
View File
@@ -23,6 +23,8 @@
\usepackage{minted} \usepackage{minted}
\setminted{fontsize=\footnotesize,breaklines,frame=single} \setminted{fontsize=\footnotesize,breaklines,frame=single}
\usepackage{tcolorbox} \usepackage{tcolorbox}
\usepackage{tikz}
\usetikzlibrary{positioning,arrows.meta,fit,backgrounds}
\usepackage{makeidx} \usepackage{makeidx}
\usepackage[colorlinks=true,citecolor=blue,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage[colorlinks=true,citecolor=blue,linkcolor=blue,urlcolor=blue]{hyperref}
\usepackage[acronym,toc]{glossaries} \usepackage[acronym,toc]{glossaries}
@@ -0,0 +1,60 @@
\begin{tikzpicture}[
font=\footnotesize,
>={Stealth[length=2mm]},
box/.style={draw, rounded corners=2pt, align=center, fill=white, inner sep=3pt},
ctr/.style={box, fill=devopsLightBlue, text width=34mm},
vol/.style={box, fill=devopsGray!12, text width=36mm},
ext/.style={box, text width=30mm},
pub/.style={->, thick, devopsBlue},
priv/.style={->, thick, devopsGreen},
adm/.style={->, thick, devopsGray, dashed},
blk/.style={->, thick, devopsRed, densely dotted},
lbl/.style={font=\scriptsize, fill=white, inner sep=1pt}
]
% External clients
\node[ext] (browser) at (0, 2.55) {Browser / Git client (any source)};
\node[ext] (ip) at (0, 1.5) {Instructor browser\\\texttt{\scriptsize http://100.49.80.94}};
\node[ext] (admin) at (0,-0.8) {Team admin (approved /32 sources)};
\node[ext] (scan) at (0,-2.5) {Any other source};
% EC2 contents
\node[vol] (cdata) at (6.6, 4.8) {\textbf{Volume} \texttt{\scriptsize inviscid\_caddy\_data}\\certificates, ACME account};
\node[ctr] (caddy) at (6.6, 2.15) {\textbf{Caddy} \texttt{\scriptsize caddy:2.10.2}\\TLS termination;\\only 80/443 publisher};
\node[ctr] (gitea) at (11.4, 3.0) {\textbf{Gitea} \texttt{\scriptsize 28.1.0}\\\texttt{\scriptsize gitea:3000}};
\node[ctr, text width=40mm] (buttons) at (11.4, 1.3) {\textbf{Color Buttons}\\\texttt{\scriptsize ssw590-group-buttons:3000}};
\node[vol] (gdata) at (16.0, 3.0) {\textbf{Volume} \texttt{\scriptsize inviscid\_gitea\_data}\\repositories, config,\\SQLite \texttt{\scriptsize gitea.db}};
\node[box, text width=34mm] (sshd) at (6.6,-0.8) {\textbf{sshd} (EC2 host), TCP 22};
\begin{scope}[on background layer]
\node[draw=devopsGreen, dashed, rounded corners, fill=devopsGreen!5, inner sep=3mm,
fit=(caddy)(gitea)(buttons),
label={[font=\scriptsize, text=devopsGreen, anchor=north west, yshift=-1pt]south west:Docker network \texttt{inviscid\_services} (private)}] (net) {};
\node[draw=devopsBlue, thick, rounded corners, inner sep=4mm,
fit=(net)(sshd)(gdata)(cdata),
label={[font=\scriptsize\bfseries, text=devopsBlue]above:EC2 \texttt{ssw590-group-web} (\texttt{us-east-1}) --- Elastic IP 100.49.80.94, no IPv6}] (ec2) {};
\end{scope}
% Security group wall
\coordinate (sgTop) at (3.25, 5.9);
\coordinate (sgBot) at (3.25,-3.0);
\draw[line width=2pt, devopsRed] (sgTop) -- (sgBot);
\node[font=\scriptsize, text=devopsRed, align=center, anchor=north, fill=white, inner sep=1pt] at ([yshift=-1mm]sgTop) {Security group\\\texttt{ssw590-web-sg}};
% Public flows (allowed by the security group)
\draw[pub] (browser.east) -- node[lbl, above, pos=0.72]{443; 80$\to$308} (caddy.west |- browser.east);
\draw[pub] (ip.east) -- node[lbl, above, pos=0.72]{80 HTTP} (caddy.west |- ip.east);
% Private flows
\draw[priv] (caddy.east |- gitea.west) -- node[lbl, above]{\texttt{\scriptsize git.inviscid.dev}} (gitea.west);
\draw[priv] (caddy.east |- buttons.west) -- node[lbl, below, pos=0.4]{by IP} (buttons.west);
\draw[priv] (caddy.north) -- (cdata.south);
\draw[priv] ([yshift=2mm]gitea.east) -- ([yshift=2mm]gdata.west |- gitea.east);
% Administrative path
\draw[adm] (admin.east) -- node[lbl, above, pos=0.72]{22 SSH} (sshd.west);
\draw[adm] (sshd.east) -- node[lbl, below]{SSH tunnel to \texttt{\scriptsize 127.0.0.1:3000}} (13.75,-0.8) |- ([yshift=-3mm]gitea.east);
% Blocked
\draw[blk] (scan.east) -- node[lbl, above, pos=0.62]{22, 3000, 222, 2019} ([xshift=-1.2mm]sgBot |- scan.east);
\node[text=devopsRed, font=\large\bfseries] at (sgBot |- scan.east) {$\times$};
\end{tikzpicture}