Files
caprover/docs/complete-webapp-tutorial.html
Kasra Bigdeli 1030fe0ec9 Deploy website
Deploy website version based on 8fe0506b3b1d032fc9021bfac183294fc655ac26
2019-01-13 15:46:30 -08:00

92 lines
17 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><title>Complete Webapp Tutorial · CaptainDuckDuck</title><meta name="viewport" content="width=device-width"/><meta name="generator" content="Docusaurus"/><meta name="description" content="&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
"/><meta name="docsearch:language" content="en"/><meta property="og:title" content="Complete Webapp Tutorial · CaptainDuckDuck"/><meta property="og:type" content="website"/><meta property="og:url" content="https://www.captainduckduck.com/index.html"/><meta property="og:description" content="&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
"/><meta property="og:image" content="https://www.captainduckduck.com/img/captainduckduck.png"/><meta name="twitter:card" content="summary"/><meta name="twitter:image" content="https://www.captainduckduck.com/img/captainduckduck.png"/><link rel="shortcut icon" href="/img/favicon.ico"/><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css"/><script type="text/javascript" src="https://buttons.github.io/buttons.js"></script><link rel="stylesheet" href="/css/main.css"/></head><body class="sideNavVisible separateOnPageNav"><div class="fixedHeaderContainer"><div class="headerWrapper wrapper"><header><a href="/"><img class="logo" src="/img/captainduckduck.png" alt="CaptainDuckDuck"/><h2 class="headerTitleWithLogo">CaptainDuckDuck</h2></a><div class="navigationWrapper navigationSlider"><nav class="slidingNav"><ul class="nav-site nav-site-internal"><li class="siteNavGroupActive"><a href="/docs/get-started.html" target="_self">Docs</a></li><li class=""><a href="https://github.com/githubsaturn/captainduckduck" target="_self">GitHub</a></li></ul></nav></div></header></div></div><div class="navPusher"><div class="docMainWrapper wrapper"><div class="container docsNavContainer" id="docsNav"><nav class="toc"><div class="toggleNav"><section class="navWrapper wrapper"><div class="navBreadcrumb wrapper"><div class="navToggle" id="navToggler"><i></i></div><h2><i></i><span>Basics</span></h2><div class="tocToggler" id="tocToggler"><i class="icon-toc"></i></div></div><div class="navGroups"><div class="navGroup"><h3 class="navGroupCategoryTitle">Basics</h3><ul><li class="navListItem"><a class="navItem" href="/docs/get-started.html">Getting Started</a></li><li class="navListItem"><a class="navItem" href="/docs/captain-definition-file.html">Captain Definition File</a></li><li class="navListItem"><a class="navItem" href="/docs/deployment-methods.html">Deployment Methods</a></li><li class="navListItem"><a class="navItem" href="/docs/app-configuration.html">App Configuration</a></li><li class="navListItem navListItemActive"><a class="navItem" href="/docs/complete-webapp-tutorial.html">Complete Webapp Tutorial</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Do More</h3><ul><li class="navListItem"><a class="navItem" href="/docs/enabling-https.html">Enabling HTTPS</a></li><li class="navListItem"><a class="navItem" href="/docs/one-click-apps.html">One-Click Apps</a></li><li class="navListItem"><a class="navItem" href="/docs/resource-monitoring.html">Resource Monitoring</a></li><li class="navListItem"><a class="navItem" href="/docs/nginx-customization.html">NGINX Config</a></li><li class="navListItem"><a class="navItem" href="/docs/app-scaling-and-cluster.html">App Scaling &amp; Cluster</a></li><li class="navListItem"><a class="navItem" href="/docs/pre-deploy-script.html">Pre-deploy Script</a></li><li class="navListItem"><a class="navItem" href="/docs/cli-commands.html">CLI Commands</a></li><li class="navListItem"><a class="navItem" href="/docs/run-locally.html">Run Locally</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Recipes and Tips</h3><ul><li class="navListItem"><a class="navItem" href="/docs/recipe-deploy-create-react-app.html">Static React App</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Help</h3><ul><li class="navListItem"><a class="navItem" href="/docs/server-purchase.html">Server Purchase</a></li><li class="navListItem"><a class="navItem" href="/docs/disk-cleanup.html">Disk Clean-Up</a></li><li class="navListItem"><a class="navItem" href="/docs/firewall.html">Firewall &amp; Port Forwarding</a></li><li class="navListItem"><a class="navItem" href="/docs/troubleshooting.html">Troubleshooting</a></li></ul></div></div></section></div><script>
document.addEventListener('DOMContentLoaded', function() {
createToggler('#navToggler', '#docsNav', 'docsSliderActive');
createToggler('#tocToggler', 'body', 'tocActive');
const headings = document.querySelector('.toc-headings');
headings && headings.addEventListener('click', function(event) {
if (event.target.tagName === 'A') {
document.body.classList.remove('tocActive');
}
}, false);
function createToggler(togglerSelector, targetSelector, className) {
var toggler = document.querySelector(togglerSelector);
var target = document.querySelector(targetSelector);
if (!toggler) {
return;
}
toggler.onclick = function(event) {
event.preventDefault();
target.classList.toggle(className);
};
}
});
</script></nav></div><div class="container mainContainer"><div class="wrapper"><div class="post"><header class="postHeader"><h1 class="postHeaderTitle">Complete Webapp Tutorial</h1></header><article><div><span><p><br/>
We want to make a webapp version of <a href="https://www.theverge.com/2017/6/26/15876006/hot-dog-app-android-silicon-valley">HOTDOG or NOT HOTDOG</a>!</p>
<h2><a class="anchor" aria-hidden="true" id="app-description"></a><a href="#app-description" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>App Description</h2>
<p>Assume we want to create a webapp that shows a list of photos with a line describing whether the image is a hotdog or not hotdog, something like this:</p>
<ul>
<li><IMAGE> Tags: Hotdog, Upload date: 2017-11-12</li>
<li><ANOTHER IMAGE> Tags: NOT Hotdog, Upload date: 2017-07-08</li>
<li><ANOTHER IMAGE> Tags: Hotdog, Upload date: 2017-07-07</li>
<li>....</li>
</ul>
<p>Anyone can upload images and our very smart Artificial Intelligence tags that image with HOTDOG or NOT-HOTDOG, then we save that image on the server and we also save upload date and tags in the database.</p>
<h2><a class="anchor" aria-hidden="true" id="app-architecture"></a><a href="#app-architecture" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>App Architecture</h2>
<p>To make this app, let's assume we decided to have the following components:</p>
<ul>
<li>NodeJS WebApp: (including static assets, frontend app, and API)</li>
<li>PHP Image Upload app - where we can make a POST request to save a photo on disk</li>
<li>MongoDB where we can store upload information (tags, upload date and etc)</li>
<li>PYTHON An Image Recognition service where we can make a POST request to know whether the image is a HOTDOG or NOT HOTDOG</li>
</ul>
<pre><code class="hljs"> +---------------------+
|<span class="hljs-string"> </span>|
|<span class="hljs-string"> NodeJS Webapp </span>|
|<span class="hljs-string"> </span>|
+---------------+------------+--------+-----------------+
|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|
|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|
|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|
|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|
|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|
+-------v-----------+ +----------v----------+ +-----------v---+
|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|
|<span class="hljs-string"> PHP File Uploader </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> Python ImageDetector</span>|<span class="hljs-string"> </span>|<span class="hljs-string"> MongoDB </span>|
|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|
+-------------------+ +---------------------+ +---------------+
</code></pre>
<h2><a class="anchor" aria-hidden="true" id="persistence-or-not"></a><a href="#persistence-or-not" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Persistence or Not</h2>
<p>CaptainDuckDuck allows you to indicate whether your app/database/service has persistence data or not. Apps with persistence can have &quot;persistent directories&quot;. These directories will be preserved if your app crashes and Captain starts a new instance of that app. All other directories will get wiped and reset to their default state if the application crashes and Captain starts a new instance of the app. In our example:</p>
<ul>
<li>WebApp: DOES NOT have/need any persistence.</li>
<li>Image Upload App: Needs a persistent directory where images get saved on disk (for example, <code>/uploaded_files</code>)</li>
<li>MongoDB. Of course, this needs persistency (where we store information), we don't want to lose the database, just because our MongoDB crashed or our server got restarted.</li>
<li>PYTHON Image Recognition app. This one does not need to save any data on disk. It simply receives an image, does some image processing and let the client know whether the image was HOTDOG or NOT HOTDOG</li>
</ul>
<h2><a class="anchor" aria-hidden="true" id="creating-services"></a><a href="#creating-services" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Creating Services:</h2>
<ul>
<li>NodeJS Web app: after you write this app, you simply create a webapp and name it <code>my-webapp</code> on Captain, you DO NOT check the persistency checkbox and you deploy your app.</li>
<li>Image Upload app: similar to webapp described above, but we'll check the persistence checkbox when creating the app. Name this app <code>image-uploader</code>. After that, we go to app details page and add a persistent directory, the path of the directory is where your app stores images. This depends on your app, in our example, let's assume it is <code>/uploaded_files</code></li>
<li>MongoDB: we'll use the one-click app installer to create an instance of MongoDB. We'll name this container <code>my-mongodb</code>. When the container (database) is created, you can go to the details page and you'll see that Captain automatically assigned some persistent directories to this container. This is where MongoDB saves its data.</li>
<li>Python Image Recognition app: Again, create a new app on Captain. We do not need to set persistence for this app as it does not save any information on the disk. Let's name this app <code>image-processor</code>.</li>
</ul>
<h2><a class="anchor" aria-hidden="true" id="internal-access"></a><a href="#internal-access" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Internal Access</h2>
<p>In order for your web-app to work. It needs to be able to talk to MongoDB instance, image uploader, and image processor. You can simply add a <code>srv-captain--</code> prefix to the name of the container if you want to access it from another container. For example in order to connect to your MongoDB instance which we name <code>my-mongodb</code>, you can add the following line to your NodeJS application (using mongoose library)</p>
<pre><code class="hljs">mongoose.connect(<span class="hljs-string">"mongodb://srv-captain--my-mongodb/mydatabase"</span>, { <span class="hljs-string">useMongoClient:</span> <span class="hljs-literal">true</span> });
</code></pre>
<p>Of course, you can add username and password to the URI, see <a href="https://stackoverflow.com/questions/7486623/mongodb-password-with-in-it">here for example</a>.</p>
<p>This is the same for other services; if you want to upload an image to your image uploader service you can just access it via <code>http://srv-captain--imageuploader</code></p>
</span></div></article></div><div class="docs-prevnext"><a class="docs-prev button" href="/docs/app-configuration.html"><span class="arrow-prev"></span><span>App Configuration</span></a><a class="docs-next button" href="/docs/enabling-https.html"><span>Enabling HTTPS</span><span class="arrow-next"></span></a></div></div></div><nav class="onPageNav"><ul class="toc-headings"><li><a href="#app-description">App Description</a></li><li><a href="#app-architecture">App Architecture</a></li><li><a href="#persistence-or-not">Persistence or Not</a></li><li><a href="#creating-services">Creating Services:</a></li><li><a href="#internal-access">Internal Access</a></li></ul></nav></div><footer class="nav-footer" id="footer"><section class="sitemap"><a href="/" class="nav-home"><img src="/img/captainduckduck.png" alt="CaptainDuckDuck" width="66" height="58"/></a><div><h5>Docs</h5><a href="/docs/en/get-started.html">Getting Started</a></div><div><h5>Community</h5><a href="https://twitter.com/search?vertical=default&amp;q=captainduckduck&amp;src=typd" target="_blank" rel="noreferrer noopener">Twitter</a><a href="https://join.slack.com/t/captainduckduck/shared_invite/enQtNDEwMjc3MjcxNjUzLWQ4YjljN2JiMGU5Nzk5NjcwMDEzNDNiMTNkOTVhNTA4YTYwOThkNDkyMTlkMDFhMzAzOTA5YjcwY2E4NWRkYzk" target="_blank" rel="noreferrer noopener">Slack Group</a></div><div><h5>More</h5><a href="https://github.com/githubsaturn/captainduckduck" target="_blank">GitHub</a><a class="github-button" href="https://github.com/githubsaturn/captainduckduck" data-icon="octicon-star" data-count-href="/githubsaturn/captainduckduck/stargazers" data-show-count="true" data-count-aria-label="# stargazers on GitHub" aria-label="Star this project on GitHub">Star</a></div></section><section class="copyright">Copyright © 2019 githubsaturn</section><script async="" src="https://www.googletagmanager.com/gtag/js?id=UA-121064489-1"></script><script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-121064489-1');
</script></footer></div></body></html>